图片edit icon

作者:
藤原
Fork(复制)
下载
嵌入
设置
BUG反馈
index.html
style.css
index.js
现在支持上传本地图片了!
            
            <!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>图片处理多卡片</title>
    <!-- 引入Font Awesome图标 -->
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
    <style>
        /* 基础样式 */
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
            font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
        }

        body {
            background: linear-gradient(to bottom, #f8fafc, #f1f5f9);
            min-height: 100vh;
            display: flex;
            flex-direction: column;
            align-items: center;
            justify-content: center;
            padding: 1rem;
            color: #334155;
            overflow-x: hidden;
        }

        .container {
            width: 100%;
            max-width: 400px;
            margin: 0 auto;
            display: flex;
            flex-direction: column;
            align-items: center;
        }

        h1 {
            font-size: 2rem;
            font-weight: 700;
            color: #0f172a;
            margin-bottom: 2rem;
            text-align: center;
        }

        /* 卡片堆叠容器 */
        .card-stack-container {
            width: 100%;
            height: 600px;
            position: relative;
            overflow: visible;
        }

        /* 卡片堆叠 */
        .card-stack {
            width: 100%;
            height: 100%;
            position: relative;
            transition: transform 0.5s ease;
        }

        /* 卡片容器 */
        .card-container {
            width: 100%;
            height: 600px;
            position: absolute;
            top: 0;
            left: 0;
            perspective: 1000px;
            transition: all 0.5s ease;
            opacity: 0;
            visibility: hidden;
            transform: translateY(40px) scale(0.9);
        }

        .card-container.active {
            opacity: 1;
            visibility: visible;
            transform: translateY(0) scale(1);
            z-index: 10;
        }

        .card-container.prev {
            opacity: 0.7;
            visibility: visible;
            transform: translateY(-40px) scale(0.9);
            z-index: 5;
        }

        .card-container.next {
            opacity: 0.7;
            visibility: visible;
            transform: translateY(40px) scale(0.9);
            z-index: 5;
        }

        /* 卡片 */
        .card {
            width: 100%;
            height: 100%;
            position: relative;
            transform-style: preserve-3d;
            transition: transform 0.8s;
            border-radius: 1rem;
            box-shadow: 0 10px 25px rgba(0, 0, 0, 0.1);
        }

        .card.flipped {
            transform: rotateY(180deg);
        }

        /* 卡片面 */
        .card-face {
            width: 100%;
            height: 100%;
            position: absolute;
            backface-visibility: hidden;
            border-radius: 1rem;
            overflow: hidden;
        }

        /* 卡片正面 */
        .card-front {
            display: flex;
            flex-direction: column;
            padding: 1.5rem;
            color: white;
        }

        /* 卡片背面 - 注意这里添加了rotateY(180deg)来修复颠倒问题 */
        .card-back {
            background: white;
            transform: rotateY(180deg);
            display: flex;
            flex-direction: column;
            padding: 1.5rem;
        }

        /* 卡片头部 */
        .card-header {
            display: flex;
            justify-content: space-between;
            align-items: center;
            margin-bottom: 1rem;
        }

        .icon-container {
            width: 2.5rem;
            height: 2.5rem;
            border-radius: 50%;
            background-color: rgba(255, 255, 255, 0.2);
            display: flex;
            align-items: center;
            justify-content: center;
        }

        .settings-icon {
            width: 2.5rem;
            height: 2.5rem;
            border-radius: 50%;
            background-color: rgba(255, 255, 255, 0.2);
            display: flex;
            align-items: center;
            justify-content: center;
            cursor: pointer;
            transition: background-color 0.2s;
        }

        .settings-icon:hover {
            background-color: rgba(255, 255, 255, 0.3);
        }

        /* 卡片标题 */
        .card-title {
            margin-bottom: 1rem;
        }

        .card-title h2 {
            font-size: 1.5rem;
            font-weight: 700;
            margin-bottom: 0.25rem;
        }

        .card-title h3 {
            font-size: 1rem;
            font-weight: 500;
            opacity: 0.8;
        }

        /* 卡片图像 */
        .card-image {
            margin-bottom: 1rem;
            flex-grow: 1;
        }

        .image-container {
            width: 100%;
            height: 100%;
            border-radius: 0.75rem;
            background-size: cover;
            background-position: center;
            box-shadow: 0 10px 15px rgba(0, 0, 0, 0.1);
        }

        /* 卡片底部 */
        .card-footer {
            margin-top: auto;
        }

        .tag {
            display: inline-flex;
            align-items: center;
            gap: 0.5rem;
            padding: 0.5rem 0.75rem;
            background-color: rgba(255, 255, 255, 0.2);
            border-radius: 9999px;
            margin-bottom: 0.75rem;
            font-size: 0.875rem;
        }

        .card-description {
            font-size: 0.875rem;
            opacity: 0.9;
        }

        /* 卡片背面头部 */
        .card-back-header {
            display: flex;
            justify-content: space-between;
            align-items: center;
            margin-bottom: 1rem;
            padding-bottom: 0.75rem;
            border-bottom: 1px solid #e2e8f0;
        }

        .card-back-header h2 {
            font-size: 1.25rem;
            font-weight: 600;
            color: #1e40af;
        }

        .close-icon {
            width: 2rem;
            height: 2rem;
            border-radius: 50%;
            background-color: #f1f5f9;
            display: flex;
            align-items: center;
            justify-content: center;
            cursor: pointer;
            transition: background-color 0.2s;
        }

        .close-icon:hover {
            background-color: #e2e8f0;
        }

        /* 卡片背面内容 */
        .card-back-content {
            flex-grow: 1;
            overflow-y: auto;
            padding-right: 0.5rem;
            margin-right: -0.5rem;
        }

        /* 上传区域 */
        .upload-area {
            border: 2px dashed #cbd5e1;
            border-radius: 0.75rem;
            padding: 1.5rem;
            text-align: center;
            cursor: pointer;
            transition: all 0.2s;
            margin-bottom: 1.5rem;
        }

        .upload-area:hover {
            background-color: #f8fafc;
            border-color: #94a3b8;
        }

        .upload-area i {
            font-size: 2rem;
            color: #64748b;
            margin-bottom: 0.75rem;
        }

        .upload-area p {
            margin-bottom: 0.25rem;
            color: #334155;
        }

        .upload-area .upload-hint {
            font-size: 0.75rem;
            color: #64748b;
        }

        /* 预览区域 */
        .preview-container {
            margin-bottom: 1.5rem;
        }

        .preview-container h3 {
            font-size: 0.875rem;
            font-weight: 600;
            margin-bottom: 0.5rem;
            color: #334155;
        }

        .preview-image-container {
            width: 100%;
            border: 1px solid #e2e8f0;
            border-radius: 0.5rem;
            overflow: hidden;
            background-color: #f8fafc;
        }

        .preview-image-container img {
            width: 100%;
            height: auto;
            display: block;
        }

        /* 设置区域 */
        .settings-section {
            background-color: #f8fafc;
            border-radius: 0.75rem;
            padding: 1rem;
            margin-bottom: 1rem;
            border: 1px solid #e2e8f0;
        }

        .settings-section h3 {
            font-size: 0.875rem;
            font-weight: 600;
            margin-bottom: 0.75rem;
            color: #1e40af;
            padding-bottom: 0.5rem;
            border-bottom: 1px solid #e2e8f0;
        }

        /* 选择控件 */
        .select-control {
            width: 100%;
            padding: 0.75rem;
            border-radius: 0.5rem;
            border: 1px solid #cbd5e1;
            font-size: 0.875rem;
            background-color: white;
            margin-bottom: 0.75rem;
            color: #334155;
        }

        /* 范围控件 */
        .range-info {
            display: flex;
            justify-content: space-between;
            font-size: 0.75rem;
            margin-bottom: 0.25rem;
            color: #64748b;
        }

        .range-control {
            width: 100%;
            height: 6px;
            -webkit-appearance: none;
            appearance: none;
            background: #e2e8f0;
            border-radius: 3px;
            outline: none;
            margin-bottom: 1rem;
        }

        .range-control::-webkit-slider-thumb {
            -webkit-appearance: none;
            appearance: none;
            width: 16px;
            height: 16px;
            background: #3b82f6;
            border-radius: 50%;
            cursor: pointer;
        }

        /* 尺寸输入 */
        .dimension-inputs {
            display: flex;
            gap: 0.75rem;
            margin-bottom: 0.75rem;
        }

        .dimension-input {
            flex: 1;
        }

        .dimension-input label {
            display: block;
            font-size: 0.75rem;
            margin-bottom: 0.25rem;
            color: #64748b;
        }

        .text-input {
            width: 100%;
            padding: 0.75rem;
            border-radius: 0.5rem;
            border: 1px solid #cbd5e1;
            font-size: 0.875rem;
            background-color: white;
        }

        /* 复选框控件 */
        .checkbox-control {
            display: flex;
            align-items: center;
            margin-bottom: 0.75rem;
            padding: 0.5rem;
            background-color: #f1f5f9;
            border-radius: 0.5rem;
        }

        .checkbox-control input {
            margin-right: 0.5rem;
            width: 1rem;
            height: 1rem;
            accent-color: #3b82f6;
        }

        .checkbox-control label {
            font-size: 0.875rem;
            color: #334155;
        }

        /* 滤镜控件 */
        .filter-control {
            margin-bottom: 0.75rem;
        }

        /* 压缩预设 */
        .compression-presets {
            display: flex;
            gap: 0.5rem;
            margin-bottom: 1rem;
        }

        .compression-preset {
            flex: 1;
            padding: 0.5rem;
            border-radius: 0.5rem;
            font-size: 0.875rem;
            text-align: center;
            cursor: pointer;
            background-color: white;
            border: 1px solid #cbd5e1;
            color: #64748b;
            transition: all 0.2s;
        }

        .compression-preset:hover:not(.active) {
            background-color: #f1f5f9;
            color: #334155;
        }

        .compression-preset.active {
            background-color: #3b82f6;
            color: white;
            border-color: #3b82f6;
        }

        /* 压缩信息 */
        .compression-info {
            background-color: white;
            padding: 0.75rem;
            border-radius: 0.5rem;
            font-size: 0.75rem;
            border: 1px solid #e2e8f0;
        }

        .compression-info div {
            display: flex;
            justify-content: space-between;
            margin-bottom: 0.25rem;
        }

        .compression-info div:last-child {
            margin-bottom: 0;
        }

        /* 卡片背面底部 */
        .card-back-footer {
            display: flex;
            justify-content: flex-end;
            gap: 0.75rem;
            padding-top: 1rem;
            border-top: 1px solid #e2e8f0;
            margin-top: 1rem;
        }

        /* 按钮 */
        .button {
            padding: 0.75rem 1rem;
            border-radius: 0.5rem;
            font-size: 0.875rem;
            font-weight: 500;
            cursor: pointer;
            transition: all 0.2s;
            display: inline-flex;
            align-items: center;
            gap: 0.5rem;
            border: none;
        }

        .button-secondary {
            background-color: white;
            border: 1px solid #cbd5e1;
            color: #334155;
        }

        .button-secondary:hover {
            background-color: #f1f5f9;
        }

        .button-primary {
            background-color: #3b82f6;
            color: white;
            box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
        }

        .button-primary:hover {
            background-color: #2563eb;
        }

        .button-primary:disabled {
            background-color: #93c5fd;
            cursor: not-allowed;
        }

        /* 通知 */
        .notification {
            position: fixed;
            bottom: 1.5rem;
            right: 1.5rem;
            padding: 1rem 1.5rem;
            border-radius: 0.5rem;
            background-color: white;
            box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1);
            z-index: 1000;
            opacity: 0;
            transform: translateY(1rem);
            transition: all 0.3s;
            max-width: 20rem;
        }

        .notification.show {
            opacity: 1;
            transform: translateY(0);
        }

        .notification.success {
            border-left: 4px solid #10b981;
        }

        .notification.error {
            border-left: 4px solid #ef4444;
        }

        .notification.info {
            border-left: 4px solid #3b82f6;
        }

        /* 滚动条样式 */
        .card-back-content::-webkit-scrollbar {
            width: 6px;
        }

        .card-back-content::-webkit-scrollbar-track {
            background: #f1f5f9;
            border-radius: 3px;
        }

        .card-back-content::-webkit-scrollbar-thumb {
            background: #cbd5e1;
            border-radius: 3px;
        }

        .card-back-content::-webkit-scrollbar-thumb:hover {
            background: #94a3b8;
        }

        /* 导航指示器 */
        .navigation-indicators {
            display: flex;
            justify-content: center;
            margin-top: 1.5rem;
        }

        .indicator {
            width: 8px;
            height: 8px;
            border-radius: 50%;
            background-color: #cbd5e1;
            margin: 0 4px;
            transition: all 0.3s;
        }

        .indicator.active {
            background-color: #3b82f6;
            transform: scale(1.5);
        }

        /* 滑动指示器 */
        .swipe-indicator {
            position: absolute;
            bottom: 1rem;
            left: 50%;
            transform: translateX(-50%);
            display: flex;
            flex-direction: column;
            align-items: center;
            color: white;
            opacity: 0.7;
            z-index: 20;
        }

        .swipe-indicator i {
            font-size: 1.5rem;
            animation: bounce 2s infinite;
        }

        @keyframes bounce {
            0%, 20%, 50%, 80%, 100% {
                transform: translateY(0);
            }
            40% {
                transform: translateY(-10px);
            }
            60% {
                transform: translateY(-5px);
            }
        }
    </style>
</head>
<body>
    <div class="container">
        <h1>图片处理工具</h1>
        
        <div class="card-stack-container">
            <div class="card-stack" id="cardStack">
                <!-- 卡片1:图片格式转换 -->
                <div class="card-container" data-index="0">
                    <div class="card" id="card-0">
                        <!-- 卡片正面 -->
                        <div class="card-face card-front" style="background: linear-gradient(to bottom, #3b82f6, #1d4ed8);">
                            <div class="card-header">
                                <div class="icon-container">
                                    <i class="fas fa-image"></i>
                                </div>
                                <div class="settings-icon flip-to-back">
                                    <i class="fas fa-cog"></i>
                                </div>
                            </div>
                            
                            <div class="card-title">
                                <h2>图片格式转换</h2>
                                <h3>支持多种格式</h3>
                            </div>
                            
                            <div class="card-image">
                                <div class="image-container" style="background-image: url('https://images.unsplash.com/photo-1552664730-d307ca884978?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=2760&q=80');"></div>
                            </div>
                            
                            <div class="card-footer">
                                <div class="tag">
                                    <i class="fas fa-image"></i>
                                    <span>支持多种格式</span>
                                </div>
                                <p class="card-description">将图片转换为JPEG、PNG、WebP等格式,调整大小、质量和应用滤镜。</p>
                            </div>
                        </div>
                        
                        <!-- 卡片背面 -->
                        <div class="card-face card-back">
                            <div class="card-back-header">
                                <h2>图片格式转换设置</h2>
                                <div class="close-icon flip-to-front">
                                    <i class="fas fa-times"></i>
                                </div>
                            </div>
                            
                            <div class="card-back-content">
                                <!-- 上传区域 -->
                                <div class="upload-area" data-card="0">
                                    <i class="fas fa-cloud-upload-alt"></i>
                                    <p>拖放图片或点击上传</p>
                                    <p class="upload-hint">支持 JPG, PNG, GIF, WEBP</p>
                                    <input type="file" class="file-input" accept="image/*" style="display: none;">
                                </div>
                                
                                <!-- 预览区域 -->
                                <div class="preview-container" data-card="0" style="display: none;">
                                    <h3>预览</h3>
                                    <div class="preview-image-container">
                                        <img class="preview-image" src="/placeholder.svg" alt="预览">
                                    </div>
                                </div>
                                
                                <!-- 格式选择 -->
                                <div class="settings-section">
                                    <h3>输出格式</h3>
                                    <select class="format-select select-control" data-card="0">
                                        <option value="jpeg">JPEG (高兼容性)</option>
                                        <option value="png">PNG (支持透明)</option>
                                        <option value="webp">WEBP (高压缩率)</option>
                                        <option value="gif">GIF (动画支持)</option>
                                    </select>
                                    
                                    <div class="quality-container" data-card="0">
                                        <div class="range-info">
                                            <span>质量</span>
                                            <span class="quality-value">80%</span>
                                        </div>
                                        <input type="range" class="quality-range range-control" min="1" max="100" value="80">
                                    </div>
                                </div>
                                
                                <!-- 图片比例选择 -->
                                <div class="settings-section">
                                    <h3>调整大小</h3>
                                    <div class="dimension-inputs">
                                        <div class="dimension-input">
                                            <label>宽度</label>
                                            <input type="number" class="width-input text-input" data-card="0" placeholder="宽度">
                                        </div>
                                        <div class="dimension-input">
                                            <label>高度</label>
                                            <input type="number" class="height-input text-input" data-card="0" placeholder="高度">
                                        </div>
                                    </div>
                                    
                                    <div class="checkbox-control">
                                        <input type="checkbox" class="lock-ratio-checkbox" data-card="0" checked>
                                        <label>锁定宽高比</label>
                                    </div>
                                    
                                    <select class="aspect-ratio-select select-control" data-card="0">
                                        <option value="original">原始比例</option>
                                        <option value="free">自由比例</option>
                                        <option value="1:1">1:1 (正方形)</option>
                                        <option value="4:3">4:3 (标准)</option>
                                        <option value="16:9">16:9 (宽屏)</option>
                                        <option value="9:16">9:16 (竖屏)</option>
                                    </select>
                                </div>
                                
                                <!-- 图像调整 -->
                                <div class="settings-section">
                                    <h3>图像调整</h3>
                                    <div class="filter-control">
                                        <div class="range-info">
                                            <span>亮度</span>
                                            <span class="brightness-value">0%</span>
                                        </div>
                                        <input type="range" class="brightness-range range-control" data-card="0" min="-100" max="100" value="0">
                                    </div>
                                    
                                    <div class="filter-control">
                                        <div class="range-info">
                                            <span>对比度</span>
                                            <span class="contrast-value">0%</span>
                                        </div>
                                        <input type="range" class="contrast-range range-control" data-card="0" min="-100" max="100" value="0">
                                    </div>
                                    
                                    <div class="filter-control">
                                        <div class="range-info">
                                            <span>饱和度</span>
                                            <span class="saturation-value">0%</span>
                                        </div>
                                        <input type="range" class="saturation-range range-control" data-card="0" min="-100" max="100" value="0">
                                    </div>
                                </div>
                                
                                <!-- 压缩选项 -->
                                <div class="settings-section">
                                    <h3>压缩选项</h3>
                                    <div class="compression-presets" data-card="0">
                                        <button class="compression-preset active" data-preset="balanced">平衡</button>
                                        <button class="compression-preset" data-preset="high-quality">高质量</button>
                                        <button class="compression-preset" data-preset="small-size">小体积</button>
                                    </div>
                                    
                                    <div class="compression-info">
                                        <div>
                                            <span>预计输出大小:</span>
                                            <span class="size-estimate">未知</span>
                                        </div>
                                        <div>
                                            <span>预计节省空间:</span>
                                            <span class="size-saving">未知</span>
                                        </div>
                                    </div>
                                </div>
                            </div>
                            
                            <div class="card-back-footer">
                                <button class="button button-secondary flip-to-front">取消</button>
                                <button class="button button-primary download-btn" data-card="0" disabled>
                                    <i class="fas fa-download"></i>
                                    下载
                                </button>
                            </div>
                        </div>
                    </div>
                </div>
                
                <!-- 卡片2:视频去水印 -->
                <div class="card-container" data-index="1">
                    <div class="card" id="card-1">
                        <!-- 卡片正面 -->
                        <div class="card-face card-front" style="background: linear-gradient(to bottom, #ef4444, #b91c1c);">
                            <div class="card-header">
                                <div class="icon-container">
                                    <i class="fas fa-video"></i>
                                </div>
                                <div class="settings-icon flip-to-back">
                                    <i class="fas fa-cog"></i>
                                </div>
                            </div>
                            
                            <div class="card-title">
                                <h2>视频去水印</h2>
                                <h3>清除视频水印</h3>
                            </div>
                            
                            <div class="card-image">
                                <div class="image-container" style="background-image: url('https://images.unsplash.com/photo-1536240478700-b869070f9279?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=2760&q=80');"></div>
                            </div>
                            
                            <div class="card-footer">
                                <div class="tag">
                                    <i class="fas fa-video"></i>
                                    <span>视频处理</span>
                                </div>
                                <p class="card-description">从视频中移除水印、标志和文字,让您的视频更加干净清晰。</p>
                            </div>
                        </div>
                        
                        <!-- 卡片背面 -->
                        <div class="card-face card-back">
                            <div class="card-back-header">
                                <h2>视频去水印设置</h2>
                                <div class="close-icon flip-to-front">
                                    <i class="fas fa-times"></i>
                                </div>
                            </div>
                            
                            <div class="card-back-content">
                                <div class="settings-section">
                                    <h3>功能开发中</h3>
                                    <p style="text-align: center; padding: 2rem 0;">此功能正在开发中,敬请期待!</p>
                                </div>
                            </div>
                            
                            <div class="card-back-footer">
                                <button class="button button-secondary flip-to-front">返回</button>
                            </div>
                        </div>
                    </div>
                </div>
                
                <!-- 卡片3:二维码生成 -->
                <div class="card-container" data-index="2">
                    <div class="card" id="card-2">
                        <!-- 卡片正面 -->
                        <div class="card-face card-front" style="background: linear-gradient(to bottom, #10b981, #047857);">
                            <div class="card-header">
                                <div class="icon-container">
                                    <i class="fas fa-qrcode"></i>
                                </div>
                                <div class="settings-icon flip-to-back">
                                    <i class="fas fa-cog"></i>
                                </div>
                            </div>
                            
                            <div class="card-title">
                                <h2>二维码生成</h2>
                                <h3>自定义二维码</h3>
                            </div>
                            
                            <div class="card-image">
                                <div class="image-container" style="background-image: url('https://images.unsplash.com/photo-1622836829543-fd98500960a9?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=2760&q=80');"></div>
                            </div>
                            
                            <div class="card-footer">
                                <div class="tag">
                                    <i class="fas fa-qrcode"></i>
                                    <span>二维码</span>
                                </div>
                                <p class="card-description">生成可自定义大小和颜色的二维码,适用于网址、文本和联系信息。</p>
                            </div>
                        </div>
                        
                        <!-- 卡片背面 -->
                        <div class="card-face card-back">
                            <div class="card-back-header">
                                <h2>二维码生成设置</h2>
                                <div class="close-icon flip-to-front">
                                    <i class="fas fa-times"></i>
                                </div>
                            </div>
                            
                            <div class="card-back-content">
                                <div class="settings-section">
                                    <h3>功能开发中</h3>
                                    <p style="text-align: center; padding: 2rem 0;">此功能正在开发中,敬请期待!</p>
                                </div>
                            </div>
                            
                            <div class="card-back-footer">
                                <button class="button button-secondary flip-to-front">返回</button>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
            
            <!-- 滑动指示器 -->
            <div class="swipe-indicator">
                <i class="fas fa-chevron-up"></i>
            </div>
        </div>
        
        <!-- 导航指示器 -->
        <div class="navigation-indicators" id="navigationIndicators">
            <div class="indicator active" data-index="0"></div>
            <div class="indicator" data-index="1"></div>
            <div class="indicator" data-index="2"></div>
        </div>
    </div>
    
    <!-- 隐藏的画布用于处理图像 -->
    <canvas id="processingCanvas" style="display: none;"></canvas>
    
    <!-- 通知 -->
    <div class="notification" id="notification"></div>
    
    <script>
        // 卡片数据
        const cardData = [
            {
                id: 0,
                title: "图片格式转换",
                originalImage: null,
                originalWidth: 0,
                originalHeight: 0,
                originalAspectRatio: 1,
                currentCompressionPreset: 'balanced'
            },
            {
                id: 1,
                title: "视频去水印"
            },
            {
                id: 2,
                title: "二维码生成"
            }
        ];

        // DOM元素
        const cardStack = document.getElementById('cardStack');
        const cardContainers = document.querySelectorAll('.card-container');
        const cards = document.querySelectorAll('.card');
        const navigationIndicators = document.getElementById('navigationIndicators');
        const indicators = document.querySelectorAll('.indicator');
        const processingCanvas = document.getElementById('processingCanvas');
        const notification = document.getElementById('notification');

        // 全局变量
        let activeCardIndex = 0;
        let startY = 0;
        let isDragging = false;
        let dragThreshold = 50; // 拖动阈值
        let touchStartTime = 0;
        let touchEndTime = 0;

        // 初始化
        document.addEventListener('DOMContentLoaded', function() {
            // 设置初始卡片状态
            updateCardPositions();
            
            // 设置事件监听器
            setupEventListeners();
        });

        // 设置事件监听器
        function setupEventListeners() {
            // 卡片堆叠滑动
            cardStack.addEventListener('mousedown', handleDragStart);
            cardStack.addEventListener('mousemove', handleDragMove);
            cardStack.addEventListener('mouseup', handleDragEnd);
            cardStack.addEventListener('mouseleave', handleDragEnd);
            
            cardStack.addEventListener('touchstart', handleDragStart, { passive: true });
            cardStack.addEventListener('touchmove', handleDragMove, { passive: false });
            cardStack.addEventListener('touchend', handleDragEnd);
            
            // 导航指示器点击
            indicators.forEach(indicator => {
                indicator.addEventListener('click', function() {
                    const index = parseInt(this.getAttribute('data-index'));
                    navigateToCard(index);
                });
            });
            
            // 卡片翻转
            document.querySelectorAll('.flip-to-back').forEach(btn => {
                btn.addEventListener('click', function() {
                    const cardId = this.closest('.card').id;
                    document.getElementById(cardId).classList.add('flipped');
                });
            });
            
            document.querySelectorAll('.flip-to-front').forEach(btn => {
                btn.addEventListener('click', function() {
                    const cardId = this.closest('.card').id;
                    document.getElementById(cardId).classList.remove('flipped');
                });
            });
            
            // 图片处理功能 - 为第一张卡片设置
            setupImageProcessingEvents();
        }

        // 设置图片处理事件
        function setupImageProcessingEvents() {
            // 上传区域
            document.querySelectorAll('.upload-area').forEach(area => {
                const cardIndex = area.getAttribute('data-card');
                const fileInput = area.querySelector('.file-input');
                
                area.addEventListener('click', function() {
                    fileInput.click();
                });
                
                area.addEventListener('dragover', function(e) {
                    e.preventDefault();
                    this.style.backgroundColor = '#f1f5f9';
                });
                
                area.addEventListener('dragleave', function() {
                    this.style.backgroundColor = '';
                });
                
                area.addEventListener('drop', function(e) {
                    e.preventDefault();
                    this.style.backgroundColor = '';
                    
                    if (e.dataTransfer.files.length) {
                        handleFileUpload(e.dataTransfer.files[0], cardIndex);
                    }
                });
                
                // 文件输入
                fileInput.addEventListener('change', function() {
                    if (this.files.length) {
                        handleFileUpload(this.files[0], cardIndex);
                    }
                });
            });
            
            // 格式选择
            document.querySelectorAll('.format-select').forEach(select => {
                const cardIndex = select.getAttribute('data-card');
                
                select.addEventListener('change', function() {
                    updateFormatUI(cardIndex);
                    updateSizeEstimate(cardIndex);
                });
            });
            
            // 质量范围
            document.querySelectorAll('.quality-range').forEach(range => {
                const cardIndex = range.closest('.quality-container').getAttribute('data-card');
                const qualityValue = range.closest('.quality-container').querySelector('.quality-value');
                
                range.addEventListener('input', function() {
                    qualityValue.textContent = `${this.value}%`;
                    updateSizeEstimate(cardIndex);
                });
            });
            
            // 尺寸输入
            document.querySelectorAll('.width-input').forEach(input => {
                const cardIndex = input.getAttribute('data-card');
                
                input.addEventListener('input', function() {
                    const lockRatio = document.querySelector(`.lock-ratio-checkbox[data-card="${cardIndex}"]`).checked;
                    const heightInput = document.querySelector(`.height-input[data-card="${cardIndex}"]`);
                    
                    if (lockRatio && this.value && cardData[cardIndex].originalAspectRatio) {
                        const width = parseInt(this.value);
                        const height = Math.round(width / cardData[cardIndex].originalAspectRatio);
                        heightInput.value = height;
                    }
                    
                    updateSizeEstimate(cardIndex);
                });
            });
            
            document.querySelectorAll('.height-input').forEach(input => {
                const cardIndex = input.getAttribute('data-card');
                
                input.addEventListener('input', function() {
                    const lockRatio = document.querySelector(`.lock-ratio-checkbox[data-card="${cardIndex}"]`).checked;
                    const widthInput = document.querySelector(`.width-input[data-card="${cardIndex}"]`);
                    
                    if (lockRatio && this.value && cardData[cardIndex].originalAspectRatio) {
                        const height = parseInt(this.value);
                        const width = Math.round(height * cardData[cardIndex].originalAspectRatio);
                        widthInput.value = width;
                    }
                    
                    updateSizeEstimate(cardIndex);
                });
            });
            
            // 锁定比例
            document.querySelectorAll('.lock-ratio-checkbox').forEach(checkbox => {
                const cardIndex = checkbox.getAttribute('data-card');
                
                checkbox.addEventListener('change', function() {
                    if (this.checked) {
                        const widthInput = document.querySelector(`.width-input[data-card="${cardIndex}"]`);
                        const heightInput = document.querySelector(`.height-input[data-card="${cardIndex}"]`);
                        
                        if (widthInput.value && cardData[cardIndex].originalAspectRatio) {
                            const width = parseInt(widthInput.value);
                            const height = Math.round(width / cardData[cardIndex].originalAspectRatio);
                            heightInput.value = height;
                        }
                    }
                });
            });
            
            // 纵横比选择
            document.querySelectorAll('.aspect-ratio-select').forEach(select => {
                const cardIndex = select.getAttribute('data-card');
                
                select.addEventListener('change', function() {
                    handleAspectRatioChange(cardIndex);
                });
            });
            
            // 亮度范围
            document.querySelectorAll('.brightness-range').forEach(range => {
                const cardIndex = range.getAttribute('data-card');
                const brightnessValue = range.closest('.filter-control').querySelector('.brightness-value');
                
                range.addEventListener('input', function() {
                    brightnessValue.textContent = `${this.value}%`;
                });
            });
            
            // 对比度范围
            document.querySelectorAll('.contrast-range').forEach(range => {
                const cardIndex = range.getAttribute('data-card');
                const contrastValue = range.closest('.filter-control').querySelector('.contrast-value');
                
                range.addEventListener('input', function() {
                    contrastValue.textContent = `${this.value}%`;
                });
            });
            
            // 饱和度范围
            document.querySelectorAll('.saturation-range').forEach(range => {
                const cardIndex = range.getAttribute('data-card');
                const saturationValue = range.closest('.filter-control').querySelector('.saturation-value');
                
                range.addEventListener('input', function() {
                    saturationValue.textContent = `${this.value}%`;
                });
            });
            
            // 压缩预设
            document.querySelectorAll('.compression-presets').forEach(presetContainer => {
                const cardIndex = presetContainer.getAttribute('data-card');
                const presets = presetContainer.querySelectorAll('.compression-preset');
                
                presets.forEach(preset => {
                    preset.addEventListener('click', function() {
                        presets.forEach(p => p.classList.remove('active'));
                        this.classList.add('active');
                        
                        cardData[cardIndex].currentCompressionPreset = this.getAttribute('data-preset');
                        
                        // 设置质量值
                        const qualityRange = document.querySelector(`.quality-range[data-card="${cardIndex}"]`);
                        const qualityValue = qualityRange.closest('.quality-container').querySelector('.quality-value');
                        
                        switch (cardData[cardIndex].currentCompressionPreset) {
                            case 'high-quality':
                                qualityRange.value = 95;
                                break;
                            case 'balanced':
                                qualityRange.value = 80;
                                break;
                            case 'small-size':
                                qualityRange.value = 60;
                                break;
                        }
                        
                        qualityValue.textContent = `${qualityRange.value}%`;
                        updateSizeEstimate(cardIndex);
                    });
                });
            });
            
            // 下载按钮
            document.querySelectorAll('.download-btn').forEach(btn => {
                const cardIndex = btn.getAttribute('data-card');
                
                btn.addEventListener('click', function() {
                    if (!cardData[cardIndex].originalImage) return;
                    
                    processAndDownloadImage(cardIndex);
                });
            });
        }

        // 处理拖动开始
        function handleDragStart(e) {
            isDragging = true;
            
            if (e.type === 'touchstart') {
                startY = e.touches[0].clientY;
                touchStartTime = new Date().getTime();
            } else {
                startY = e.clientY;
                touchStartTime = new Date().getTime();
            }
        }

        // 处理拖动移动
        function handleDragMove(e) {
            if (!isDragging) return;
            
            let currentY;
            if (e.type === 'touchmove') {
                currentY = e.touches[0].clientY;
                e.preventDefault(); // 防止页面滚动
            } else {
                currentY = e.clientY;
            }
            
            const deltaY = currentY - startY;
            
            // 如果拖动距离超过阈值,防止页面滚动
            if (Math.abs(deltaY) > 10) {
                e.preventDefault();
            }
        }

        // 处理拖动结束
        function handleDragEnd(e) {
            if (!isDragging) return;
            
            let endY;
            if (e.type === 'touchend') {
                endY = e.changedTouches[0].clientY;
            } else {
                endY = e.clientY;
            }
            
            touchEndTime = new Date().getTime();
            const deltaY = endY - startY;
            const deltaTime = touchEndTime - touchStartTime;
            const speed = Math.abs(deltaY) / deltaTime;
            
            // 如果拖动速度快或距离大,切换卡片
            if (speed > 0.5 || Math.abs(deltaY) > dragThreshold) {
                if (deltaY > 0) {
                    // 向下滑动,显示上一张卡片
                    navigateToPrevCard();
                } else {
                    // 向上滑动,显示下一张卡片
                    navigateToNextCard();
                }
            }
            
            isDragging = false;
        }

        // 导航到下一张卡片
        function navigateToNextCard() {
            if (activeCardIndex < cardContainers.length - 1) {
                navigateToCard(activeCardIndex + 1);
            }
        }

        // 导航到上一张卡片
        function navigateToPrevCard() {
            if (activeCardIndex > 0) {
                navigateToCard(activeCardIndex - 1);
            }
        }

        // 导航到指定卡片
        function navigateToCard(index) {
            if (index < 0 || index >= cardContainers.length) return;
            
            activeCardIndex = index;
            updateCardPositions();
            updateIndicators();
        }

        // 更新卡片位置
        function updateCardPositions() {
            cardContainers.forEach((container, index) => {
                container.classList.remove('active', 'prev', 'next');
                
                if (index === activeCardIndex) {
                    container.classList.add('active');
                } else if (index === activeCardIndex - 1) {
                    container.classList.add('prev');
                } else if (index === activeCardIndex + 1) {
                    container.classList.add('next');
                }
            });
        }

        // 更新指示器
        function updateIndicators() {
            indicators.forEach((indicator, index) => {
                if (index === activeCardIndex) {
                    indicator.classList.add('active');
                } else {
                    indicator.classList.remove('active');
                }
            });
        }

        // 处理文件上传
        function handleFileUpload(file, cardIndex) {
            if (!file.type.startsWith('image/')) {
                showNotification('请选择有效的图片文件', 'error');
                return;
            }
            
            const reader = new FileReader();
            
            reader.onload = function(e) {
                const img = new Image();
                
                img.onload = function() {
                    // 保存原始图像
                    cardData[cardIndex].originalImage = img;
                    cardData[cardIndex].originalWidth = img.width;
                    cardData[cardIndex].originalHeight = img.height;
                    cardData[cardIndex].originalAspectRatio = img.width / img.height;
                    
                    // 更新预览
                    const previewContainer = document.querySelector(`.preview-container[data-card="${cardIndex}"]`);
                    const previewImage = previewContainer.querySelector('.preview-image');
                    previewImage.src = e.target.result;
                    previewContainer.style.display = 'block';
                    
                    // 更新尺寸输入
                    const widthInput = document.querySelector(`.width-input[data-card="${cardIndex}"]`);
                    const heightInput = document.querySelector(`.height-input[data-card="${cardIndex}"]`);
                    widthInput.value = img.width;
                    heightInput.value = img.height;
                    
                    // 启用下载按钮
                    const downloadBtn = document.querySelector(`.download-btn[data-card="${cardIndex}"]`);
                    downloadBtn.disabled = false;
                    
                    // 更新大小估计
                    updateSizeEstimate(cardIndex);
                };
                
                img.src = e.target.result;
            };
            
            reader.onerror = function() {
                showNotification('读取文件时出错', 'error');
            };
            
            reader.readAsDataURL(file);
        }

        // 更新格式相关UI
        function updateFormatUI(cardIndex) {
            const formatSelect = document.querySelector(`.format-select[data-card="${cardIndex}"]`);
            const qualityContainer = document.querySelector(`.quality-container[data-card="${cardIndex}"]`);
            const format = formatSelect.value;
            
            if (format === 'jpeg' || format === 'webp') {
                qualityContainer.style.display = 'block';
            } else {
                qualityContainer.style.display = 'none';
            }
        }

        // 处理纵横比变化
        function handleAspectRatioChange(cardIndex) {
            const aspectRatioSelect = document.querySelector(`.aspect-ratio-select[data-card="${cardIndex}"]`);
            const widthInput = document.querySelector(`.width-input[data-card="${cardIndex}"]`);
            const heightInput = document.querySelector(`.height-input[data-card="${cardIndex}"]`);
            const lockRatioCheckbox = document.querySelector(`.lock-ratio-checkbox[data-card="${cardIndex}"]`);
            
            const value = aspectRatioSelect.value;
            
            if (value === 'original' && cardData[cardIndex].originalImage) {
                widthInput.value = cardData[cardIndex].originalWidth;
                heightInput.value = cardData[cardIndex].originalHeight;
                lockRatioCheckbox.checked = true;
                return;
            }
            
            if (value === 'free') {
                lockRatioCheckbox.checked = false;
                return;
            }
            
            lockRatioCheckbox.checked = true;
            
            if (!widthInput.value || !cardData[cardIndex].originalImage) return;
            
            let ratio;
            
            switch (value) {
                case '1:1':
                    ratio = 1;
                    break;
                case '4:3':
                    ratio = 4/3;
                    break;
                case '16:9':
                    ratio = 16/9;
                    break;
                case '9:16':
                    ratio = 9/16;
                    break;
                default:
                    ratio = cardData[cardIndex].originalAspectRatio;
            }
            
            const width = parseInt(widthInput.value);
            const height = Math.round(width / ratio);
            heightInput.value = height;
            
            updateSizeEstimate(cardIndex);
        }

        // 更新大小估计
        function updateSizeEstimate(cardIndex) {
            if (!cardData[cardIndex].originalImage) return;
            
            // 获取设置
            const formatSelect = document.querySelector(`.format-select[data-card="${cardIndex}"]`);
            const qualityRange = document.querySelector(`.quality-range[data-card="${cardIndex}"]`);
            const widthInput = document.querySelector(`.width-input[data-card="${cardIndex}"]`);
            const heightInput = document.querySelector(`.height-input[data-card="${cardIndex}"]`);
            const sizeEstimate = document.querySelector(`.card-container[data-index="${cardIndex}"] .size-estimate`);
            const sizeSaving = document.querySelector(`.card-container[data-index="${cardIndex}"] .size-saving`);
            
            const format = formatSelect.value;
            const quality = parseInt(qualityRange.value) / 100;
            const width = widthInput.value ? parseInt(widthInput.value) : cardData[cardIndex].originalWidth;
            const height = heightInput.value ? parseInt(heightInput.value) : cardData[cardIndex].originalHeight;
            
            // 估算原始大小 (基于图像尺寸和颜色深度)
            const originalSize = cardData[cardIndex].originalWidth * cardData[cardIndex].originalHeight * 4; // 假设每像素4字节 (RGBA)
            
            // 估算输出大小
            let estimatedSize;
            
            if (format === 'jpeg') {
                estimatedSize = width * height * 4 * quality * 0.25; // JPEG压缩率约为25%
            } else if (format === 'png') {
                estimatedSize = width * height * 4 * 0.8; // PNG压缩率约为80%
            } else if (format === 'webp') {
                estimatedSize = width * height * 4 * quality * 0.2; // WebP压缩率约为20%
            } else {
                estimatedSize = width * height * 4 * 0.7; // GIF压缩率约为70%
            }
            
            // 更新UI
            sizeEstimate.textContent = formatFileSize(estimatedSize);
            
            // 计算节省空间
            const saving = originalSize - estimatedSize;
            const savingPercentage = Math.round((saving / originalSize) * 100);
            
            if (saving > 0) {
                sizeSaving.textContent = `${formatFileSize(saving)} (${savingPercentage}%)`;
                sizeSaving.style.color = '#10b981'; // 绿色
            } else {
                sizeSaving.textContent = `增加 ${formatFileSize(Math.abs(saving))} (${Math.abs(savingPercentage)}%)`;
                sizeSaving.style.color = '#ef4444'; // 红色
            }
        }

        // 处理并下载图像
        function processAndDownloadImage(cardIndex) {
            if (!cardData[cardIndex].originalImage) return;
            
            // 获取设置
            const formatSelect = document.querySelector(`.format-select[data-card="${cardIndex}"]`);
            const qualityRange = document.querySelector(`.quality-range[data-card="${cardIndex}"]`);
            const widthInput = document.querySelector(`.width-input[data-card="${cardIndex}"]`);
            const heightInput = document.querySelector(`.height-input[data-card="${cardIndex}"]`);
            const brightnessRange = document.querySelector(`.brightness-range[data-card="${cardIndex}"]`);
            const contrastRange = document.querySelector(`.contrast-range[data-card="${cardIndex}"]`);
            const saturationRange = document.querySelector(`.saturation-range[data-card="${cardIndex}"]`);
            
            const format = formatSelect.value;
            const quality = parseInt(qualityRange.value) / 100;
            const width = widthInput.value ? parseInt(widthInput.value) : cardData[cardIndex].originalWidth;
            const height = heightInput.value ? parseInt(heightInput.value) : cardData[cardIndex].originalHeight;
            const brightness = 1 + parseInt(brightnessRange.value) / 100;
            const contrast = 1 + parseInt(contrastRange.value) / 100;
            const saturation = 1 + parseInt(saturationRange.value) / 100;
            
            // 设置画布大小
            processingCanvas.width = width;
            processingCanvas.height = height;
            
            // 获取上下文
            const ctx = processingCanvas.getContext('2d');
            
            // 绘制图像
            ctx.drawImage(cardData[cardIndex].originalImage, 0, 0, width, height);
            
            // 应用滤镜
            if (brightness !== 1 || contrast !== 1 || saturation !== 1) {
                const imageData = ctx.getImageData(0, 0, width, height);
                const data = imageData.data;
                
                for (let i = 0; i < data.length; i += 4) {
                    // 亮度
                    data[i] = data[i] * brightness;
                    data[i + 1] = data[i + 1] * brightness;
                    data[i + 2] = data[i + 2] * brightness;
                    
                    // 对比度
                    data[i] = (data[i] - 128) * contrast + 128;
                    data[i + 1] = (data[i + 1] - 128) * contrast + 128;
                    data[i + 2] = (data[i + 2] - 128) * contrast + 128;
                    
                    // 饱和度
                    if (saturation !== 1) {
                        const gray = 0.2989 * data[i] + 0.587 * data[i + 1] + 0.114 * data[i + 2];
                        data[i] = gray * (1 - saturation) + data[i] * saturation;
                        data[i + 1] = gray * (1 - saturation) + data[i + 1] * saturation;
                        data[i + 2] = gray * (1 - saturation) + data[i + 2] * saturation;
                    }
                }
                
                ctx.putImageData(imageData, 0, 0);
            }
            
            // 导出图像
            let dataUrl;
            if (format === 'jpeg' || format === 'webp') {
                dataUrl = processingCanvas.toDataURL(`image/${format}`, quality);
            } else {
                dataUrl = processingCanvas.toDataURL(`image/${format}`);
            }
            
            // 创建下载链接
            const link = document.createElement('a');
            link.href = dataUrl;
            link.download = `processed_image.${format}`;
            link.click();
            
            // 显示通知
            showNotification('图片已成功下载', 'success');
        }

        // 显示通知
        function showNotification(message, type = 'info') {
            notification.textContent = message;
            notification.className = `notification ${type}`;
            notification.classList.add('show');
            
            setTimeout(function() {
                notification.classList.remove('show');
            }, 3000);
        }

        // 格式化文件大小
        function formatFileSize(bytes) {
            if (bytes === 0) return '0 Bytes';
            const k = 1024;
            const sizes = ['Bytes', 'KB', 'MB', 'GB'];
            const i = Math.floor(Math.log(bytes) / Math.log(k));
            return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
        }
    </script>
</body>
</html>
        
预览
控制台