最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

HTML+CSS+JS實(shí)現(xiàn)簡單照片壓縮工具的示例詳解

 更新時間:2025年10月11日 08:59:44   作者:可愛的秋秋啊  
這篇文章主要為大家詳細(xì)介紹了如何使用HTML開發(fā)一個瀏覽器端照片壓縮工具,支持上傳圖片,調(diào)整壓縮質(zhì)量,實(shí)時預(yù)覽效果并下載,需要的小伙伴可以了解下

用HTML開發(fā)一個瀏覽器端照片壓縮工具,支持上傳圖片、調(diào)整壓縮質(zhì)量、實(shí)時預(yù)覽效果并下載。

詳細(xì)需求如下:

1. 需要確定壓縮后的圖片尺寸和大小一定要比壓縮前小

2. 界面中可以直尺查看,壓縮前的照片和壓縮后的照片 ,如果沒有的話就顯示暫無

3. 可以選擇自定義選擇輸出格式

4. 壓縮前后都是base64格式座位 img 標(biāo)簽的src 值

5. 上傳圖片組件一定要方式重復(fù)上傳

6. 輸出格式如果選為質(zhì)量較高的png格式圖片的時候,壓縮后的大小一定要比壓縮前小

7. 最終壓縮后的圖片的尺寸和大小一定要小于壓縮前的

8. 哪怕是png(無損壓縮)也要保證壓縮后的大小一定小于壓縮前的,要強(qiáng)制壓縮

完整代碼如下:

<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="external nofollow"  rel="stylesheet">
    
    <!-- 配置Tailwind自定義顏色和字體 -->
    <script>
        tailwind.config = {
            theme: {
                extend: {
                    colors: {
                        primary: '#3B82F6',
                        secondary: '#10B981',
                        neutral: '#64748B',
                        dark: '#1E293B',
                        light: '#F8FAFC'
                    },
                    fontFamily: {
                        inter: ['Inter', 'system-ui', 'sans-serif'],
                    },
                }
            }
        }
    </script>
    
    <style type="text/tailwindcss">
        @layer utilities {
            .content-auto {
                content-visibility: auto;
            }
            .shadow-soft {
                box-shadow: 0 4px 20px rgba(0, 0, 0, 0.08);
            }
            .transition-custom {
                transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
            }
            .scale-hover {
                @apply hover:scale-105 transition-all duration-300;
            }
        }
    </style>
</head>
<body class="font-inter bg-gray-50 text-dark min-h-screen flex flex-col">
    <!-- 頂部導(dǎo)航 -->
    <header class="bg-white shadow-sm py-4 px-6 md:px-12">
        <div class="container mx-auto flex justify-between items-center">
            <div class="flex items-center space-x-2">
                <i class="fa fa-compress text-primary text-2xl"></i>
                <h1 class="text-xl md:text-2xl font-bold bg-gradient-to-r from-primary to-secondary bg-clip-text text-transparent">
                    高效照片壓縮工具
                </h1>
            </div>
            <div class="text-sm text-neutral hidden md:block">
                瀏覽器端處理 · 保護(hù)隱私 · 免費(fèi)使用
            </div>
        </div>
    </header>

    <!-- 主要內(nèi)容區(qū) -->
    <main class="flex-grow container mx-auto p-4 md:p-8 lg:p-12">
        <!-- 上傳區(qū)域 -->
        <section class="mb-10">
            <div id="upload-container" class="bg-white rounded-xl shadow-soft p-6 md:p-8 border-2 border-dashed border-gray-200 hover:border-primary transition-custom">
                <div class="flex flex-col items-center justify-center text-center">
                    <i class="fa fa-cloud-upload text-5xl text-primary mb-4"></i>
                    <h2 class="text-xl font-semibold mb-2">上傳圖片</h2>
                    <p class="text-neutral mb-6 max-w-md">支持JPG、PNG等格式,文件將在瀏覽器中處理,不會上傳到服務(wù)器</p>
                    
                    <label for="file-upload" class="bg-primary hover:bg-primary/90 text-white font-medium py-3 px-8 rounded-lg cursor-pointer transition-custom scale-hover flex items-center">
                        <i class="fa fa-file-image-o mr-2"></i>選擇圖片
                    </label>
                    <input id="file-upload" type="file" accept="image/*" class="hidden">
                    
                    <p id="file-name" class="mt-4 text-sm text-neutral hidden"></p>
                    <button id="reset-upload" class="mt-4 text-neutral hover:text-red-500 transition-custom hidden">
                        <i class="fa fa-times-circle mr-1"></i> 重新選擇
                    </button>
                </div>
            </div>
        </section>

        <!-- 壓縮設(shè)置區(qū)域 -->
        <section id="compression-settings" class="mb-10 hidden">
            <div class="bg-white rounded-xl shadow-soft p-6 md:p-8">
                <h2 class="text-xl font-semibold mb-6 flex items-center">
                    <i class="fa fa-sliders text-primary mr-2"></i>壓縮設(shè)置
                </h2>
                
                <div class="grid grid-cols-1 md:grid-cols-2 gap-8">
                    <!-- 質(zhì)量設(shè)置 -->
                    <div>
                        <label for="quality" class="block text-sm font-medium text-gray-700 mb-2">
                            壓縮質(zhì)量: <span id="quality-value">80</span>%
                        </label>
                        <input type="range" id="quality" min="1" max="100" value="80" class="w-full h-2 bg-gray-200 rounded-lg appearance-none cursor-pointer accent-primary">
                        <p class="text-xs text-neutral mt-1">數(shù)值越低,壓縮率越高,畫質(zhì)可能下降越明顯</p>
                    </div>
                    
                    <!-- 輸出格式 -->
                    <div>
                        <label for="output-format" class="block text-sm font-medium text-gray-700 mb-2">
                            輸出格式
                        </label>
                        <select id="output-format" class="w-full p-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary focus:border-primary transition-custom">
                            <option value="jpeg">JPEG</option>
                            <option value="png">PNG</option>
                            <option value="webp">WebP (現(xiàn)代格式)</option>
                        </select>
                        <p class="text-xs text-neutral mt-1">選擇壓縮后的圖片格式</p>
                    </div>
                </div>
                
                <div class="mt-6 flex justify-center">
                    <button id="compress-btn" class="bg-secondary hover:bg-secondary/90 text-white font-medium py-3 px-8 rounded-lg transition-custom scale-hover flex items-center">
                        <i class="fa fa-cog mr-2"></i>開始壓縮
                    </button>
                </div>
            </div>
        </section>

        <!-- 預(yù)覽區(qū)域 -->
        <section id="preview-section" class="mb-10 hidden">
            <div class="bg-white rounded-xl shadow-soft p-6 md:p-8">
                <h2 class="text-xl font-semibold mb-6 flex items-center">
                    <i class="fa fa-eye text-primary mr-2"></i>壓縮前后對比
                </h2>
                
                <div class="grid grid-cols-1 md:grid-cols-2 gap-8">
                    <!-- 原圖預(yù)覽 -->
                    <div class="flex flex-col items-center">
                        <h3 class="text-lg font-medium mb-4">原圖</h3>
                        <div class="relative w-full max-w-md h-64 md:h-80 bg-gray-100 rounded-lg flex items-center justify-center overflow-hidden mb-4">
                            <img id="original-image" src="" alt="原始圖片預(yù)覽" class="max-w-full max-h-full object-contain">
                            <div id="original-placeholder" class="text-center p-4">
                                <i class="fa fa-image text-4xl text-gray-300 mb-2"></i>
                                <p class="text-gray-400">暫無圖片</p>
                            </div>
                        </div>
                        <div class="text-sm text-neutral w-full max-w-md">
                            <p><span class="font-medium">尺寸:</span> <span id="original-dimensions">--</span></p>
                            <p><span class="font-medium">大小:</span> <span id="original-size">--</span></p>
                            <p><span class="font-medium">格式:</span> <span id="original-format">--</span></p>
                        </div>
                    </div>
                    
                    <!-- 壓縮后預(yù)覽 -->
                    <div class="flex flex-col items-center">
                        <h3 class="text-lg font-medium mb-4">壓縮后</h3>
                        <div class="relative w-full max-w-md h-64 md:h-80 bg-gray-100 rounded-lg flex items-center justify-center overflow-hidden mb-4">
                            <img id="compressed-image" src="" alt="壓縮后圖片預(yù)覽" class="max-w-full max-h-full object-contain">
                            <div id="compressed-placeholder" class="text-center p-4">
                                <i class="fa fa-image text-4xl text-gray-300 mb-2"></i>
                                <p class="text-gray-400">暫無圖片</p>
                            </div>
                        </div>
                        <div class="text-sm text-neutral w-full max-w-md">
                            <p><span class="font-medium">尺寸:</span> <span id="compressed-dimensions">--</span></p>
                            <p><span class="font-medium">大小:</span> <span id="compressed-size">--</span></p>
                            <p><span class="font-medium">格式:</span> <span id="compressed-format">--</span></p>
                        </div>
                    </div>
                </div>
                
                <div class="mt-8 flex justify-center">
                    <button id="download-btn" class="bg-primary hover:bg-primary/90 text-white font-medium py-3 px-8 rounded-lg transition-custom scale-hover flex items-center disabled:opacity-50 disabled:cursor-not-allowed" disabled="">
                        <i class="fa fa-download mr-2"></i>下載壓縮圖片
                    </button>
                </div>
            </div>
        </section>
        
        <!-- 提示信息區(qū)域 -->
        <section id="info-section" class="bg-blue-50 border-l-4 border-primary p-4 rounded-r-lg mb-10 hidden">
            <div class="flex">
                <div class="flex-shrink-0">
                    <i class="fa fa-info-circle text-primary"></i>
                </div>
                <div class="ml-3">
                    <p class="text-sm text-blue-700" id="info-message">
                        提示信息將顯示在這里
                    </p>
                </div>
            </div>
        </section>
    </main>

    <!-- 頁腳 -->
    <footer class="bg-white border-t border-gray-200 py-6 px-6">
        <div class="container mx-auto text-center text-sm text-neutral">
            <p>高效照片壓縮工具 ? 2025 - 所有圖片均在您的瀏覽器中處理,不會上傳到任何服務(wù)器</p>
        </div>
    </footer>

    <!-- 加載動畫 -->
    <div id="loading-overlay" class="fixed inset-0 bg-black/50 flex items-center justify-center z-50 hidden">
        <div class="bg-white p-6 rounded-lg shadow-lg flex items-center">
            <div class="animate-spin rounded-full h-8 w-8 border-b-2 border-primary mr-4"></div>
            <p class="font-medium">正在處理圖片...</p>
        </div>
    </div>

    <script>
        // 全局變量
        let originalImageData = null;
        let compressedImageData = null;
        let isImageUploaded = false;
        
        // DOM 元素
        const fileUpload = document.getElementById('file-upload');
        const fileName = document.getElementById('file-name');
        const resetUpload = document.getElementById('reset-upload');
        const uploadContainer = document.getElementById('upload-container');
        const compressionSettings = document.getElementById('compression-settings');
        const previewSection = document.getElementById('preview-section');
        const infoSection = document.getElementById('info-section');
        const infoMessage = document.getElementById('info-message');
        const qualitySlider = document.getElementById('quality');
        const qualityValue = document.getElementById('quality-value');
        const outputFormat = document.getElementById('output-format');
        const compressBtn = document.getElementById('compress-btn');
        const downloadBtn = document.getElementById('download-btn');
        const originalImage = document.getElementById('original-image');
        const compressedImage = document.getElementById('compressed-image');
        const originalPlaceholder = document.getElementById('original-placeholder');
        const compressedPlaceholder = document.getElementById('compressed-placeholder');
        const originalDimensions = document.getElementById('original-dimensions');
        const originalSize = document.getElementById('original-size');
        const originalFormat = document.getElementById('original-format');
        const compressedDimensions = document.getElementById('compressed-dimensions');
        const compressedSize = document.getElementById('compressed-size');
        const compressedFormat = document.getElementById('compressed-format');
        const loadingOverlay = document.getElementById('loading-overlay');
        
        // 事件監(jiān)聽器
        fileUpload.addEventListener('change', handleFileUpload);
        resetUpload.addEventListener('click', resetUploadedFile);
        qualitySlider.addEventListener('input', updateQualityValue);
        compressBtn.addEventListener('click', compressImage);
        downloadBtn.addEventListener('click', downloadCompressedImage);
        
        // 顯示質(zhì)量值
        function updateQualityValue() {
            qualityValue.textContent = qualitySlider.value;
        }
        
        // 處理文件上傳
        function handleFileUpload(e) {
            const file = e.target.files[0];
            if (!file) return;
            
            // 檢查是否是圖片文件
            if (!file.type.startsWith('image/')) {
                showInfo('請上傳有效的圖片文件', 'error');
                resetUploadedFile();
                return;
            }
            
            // 防止重復(fù)上傳相同文件
            if (isImageUploaded) {
                showInfo('已上傳圖片,請先壓縮或重新選擇', 'warning');
                return;
            }
            
            // 讀取文件并顯示
            const reader = new FileReader();
            reader.onload = function(event) {
                const base64Data = event.target.result;
                
                // 創(chuàng)建圖片對象獲取尺寸信息
                const img = new Image();
                img.onload = function() {
                    // 存儲原始圖片數(shù)據(jù)
                    originalImageData = {
                        base64: base64Data,
                        width: img.width,
                        height: img.height,
                        size: file.size,
                        format: file.type.split('/')[1]
                    };
                    
                    // 更新UI
                    updateOriginalImageUI();
                    fileName.textContent = file.name;
                    fileName.classList.remove('hidden');
                    resetUpload.classList.remove('hidden');
                    compressionSettings.classList.remove('hidden');
                    previewSection.classList.remove('hidden');
                    uploadContainer.classList.remove('border-dashed', 'border-gray-200');
                    uploadContainer.classList.add('border-primary');
                    
                    isImageUploaded = true;
                    showInfo('圖片上傳成功,請調(diào)整壓縮設(shè)置并點(diǎn)擊"開始壓縮"', 'info');
                };
                img.src = base64Data;
            };
            reader.readAsDataURL(file);
        }
        
        // 重置上傳
        function resetUploadedFile() {
            fileUpload.value = '';
            fileName.classList.add('hidden');
            resetUpload.classList.add('hidden');
            uploadContainer.classList.add('border-dashed', 'border-gray-200');
            uploadContainer.classList.remove('border-primary');
            
            // 重置圖片數(shù)據(jù)
            originalImageData = null;
            compressedImageData = null;
            isImageUploaded = false;
            
            // 重置UI
            resetOriginalImageUI();
            resetCompressedImageUI();
            compressionSettings.classList.add('hidden');
            previewSection.classList.add('hidden');
            infoSection.classList.add('hidden');
            downloadBtn.disabled = true;
        }
        
        // 更新原始圖片UI
        function updateOriginalImageUI() {
            originalImage.src = originalImageData.base64;
            originalImage.classList.remove('hidden');
            originalPlaceholder.classList.add('hidden');
            originalDimensions.textContent = `${originalImageData.width} × ${originalImageData.height} 像素`;
            originalSize.textContent = formatFileSize(originalImageData.size);
            originalFormat.textContent = originalImageData.format.toUpperCase();
        }
        
        // 重置原始圖片UI
        function resetOriginalImageUI() {
            originalImage.src = '';
            originalImage.classList.add('hidden');
            originalPlaceholder.classList.remove('hidden');
            originalDimensions.textContent = '--';
            originalSize.textContent = '--';
            originalFormat.textContent = '--';
        }
        
        // 重置壓縮圖片UI
        function resetCompressedImageUI() {
            compressedImage.src = '';
            compressedImage.classList.add('hidden');
            compressedPlaceholder.classList.remove('hidden');
            compressedDimensions.textContent = '--';
            compressedSize.textContent = '--';
            compressedFormat.textContent = '--';
        }
        
        // 顯示提示信息
        function showInfo(message, type = 'info') {
            infoMessage.textContent = message;
            infoSection.classList.remove('hidden');
            
            // 設(shè)置不同類型的樣式
            infoSection.className = '';
            if (type === 'info') {
                infoSection.classList.add('bg-blue-50', 'border-l-4', 'border-primary', 'p-4', 'rounded-r-lg', 'mb-10');
                infoMessage.classList.add('text-blue-700');
                infoMessage.classList.remove('text-yellow-700', 'text-red-700');
            } else if (type === 'warning') {
                infoSection.classList.add('bg-yellow-50', 'border-l-4', 'border-yellow-400', 'p-4', 'rounded-r-lg', 'mb-10');
                infoMessage.classList.add('text-yellow-700');
                infoMessage.classList.remove('text-blue-700', 'text-red-700');
            } else if (type === 'error') {
                infoSection.classList.add('bg-red-50', 'border-l-4', 'border-red-400', 'p-4', 'rounded-r-lg', 'mb-10');
                infoMessage.classList.add('text-red-700');
                infoMessage.classList.remove('text-blue-700', 'text-yellow-700');
            }
            
            // 5秒后自動隱藏
            setTimeout(() => {
                infoSection.classList.add('hidden');
            }, 5000);
        }
        
        // 格式化文件大小
        function formatFileSize(bytes) {
            if (bytes < 1024) return bytes + ' B';
            else if (bytes < 1048576) return (bytes / 1024).toFixed(2) + ' KB';
            else return (bytes / 1048576).toFixed(2) + ' MB';
        }
        
        // 計算Base64數(shù)據(jù)大小
        function getBase64FileSize(base64String) {
            // Base64編碼的字符串大小計算: (長度 * 3) / 4 - 填充字符數(shù)
            const padding = (base64String.endsWith('==') ? 2 : base64String.endsWith('=') ? 1 : 0);
            const fileSizeInBytes = (base64String.length * 3 / 4) - padding;
            return Math.round(fileSizeInBytes);
        }
        
        // 壓縮圖片
        function compressImage() {
            if (!originalImageData) return;
            
            showLoading(true);
            resetCompressedImageUI();
            
            // 使用setTimeout避免UI阻塞
            setTimeout(() => {
                try {
                    const img = new Image();
                    img.onload = function() {
                        // 創(chuàng)建canvas元素
                        const canvas = document.createElement('canvas');
                        const ctx = canvas.getContext('2d');
                        
                        // 設(shè)置初始尺寸為原圖尺寸
                        let width = img.width;
                        let height = img.height;
                        
                        // 獲取用戶設(shè)置
                        const quality = qualitySlider.value / 100;
                        const format = outputFormat.value;
                        
                        // 首次壓縮嘗試
                        canvas.width = width;
                        canvas.height = height;
                        ctx.drawImage(img, 0, 0, width, height);
                        
                        // 根據(jù)格式獲取Base64數(shù)據(jù)
                        let base64Data;
                        if (format === 'jpeg') {
                            base64Data = canvas.toDataURL('image/jpeg', quality);
                        } else if (format === 'webp') {
                            base64Data = canvas.toDataURL('image/webp', quality);
                        } else { // png
                            // PNG格式不支持quality參數(shù),我們需要通過其他方式壓縮
                            base64Data = canvas.toDataURL('image/png');
                        }
                        
                        // 計算壓縮后大小
                        let compressedSize = getBase64FileSize(base64Data.split(',')[1]);
                        
                        // 強(qiáng)制確保壓縮后大小小于原圖大小
                        let iterations = 0;
                        const maxIterations = 20; // 防止無限循環(huán)
                        
                        // 如果壓縮后的大小仍然大于原圖,繼續(xù)壓縮
                        while (compressedSize >= originalImageData.size && iterations < maxIterations) {
                            iterations++;
                            
                            // 每次迭代減小10%的尺寸
                            width = Math.round(width * 0.9);
                            height = Math.round(height * 0.9);
                            
                            // 確保尺寸不會過小
                            if (width < 10 || height < 10) break;
                            
                            // 重新繪制并壓縮
                            canvas.width = width;
                            canvas.height = height;
                            ctx.drawImage(img, 0, 0, width, height);
                            
                            if (format === 'jpeg') {
                                base64Data = canvas.toDataURL('image/jpeg', Math.max(0.1, quality - (iterations * 0.1)));
                            } else if (format === 'webp') {
                                base64Data = canvas.toDataURL('image/webp', Math.max(0.1, quality - (iterations * 0.1)));
                            } else { // png
                                // 對于PNG,我們通過減小尺寸來壓縮
                                base64Data = canvas.toDataURL('image/png');
                            }
                            
                            compressedSize = getBase64FileSize(base64Data.split(',')[1]);
                        }
                        
                        // 存儲壓縮后的圖片數(shù)據(jù)
                        compressedImageData = {
                            base64: base64Data,
                            width: width,
                            height: height,
                            size: compressedSize,
                            format: format
                        };
                        
                        // 更新UI
                        updateCompressedImageUI();
                        downloadBtn.disabled = false;
                        
                        // 計算壓縮率
                        const rate = ((1 - compressedSize / originalImageData.size) * 100).toFixed(1);
                        showInfo(`圖片壓縮成功,壓縮率: ${rate}%`, 'info');
                        
                        showLoading(false);
                    };
                    img.src = originalImageData.base64;
                } catch (error) {
                    showInfo(`壓縮失敗: ${error.message}`, 'error');
                    showLoading(false);
                }
            }, 100);
        }
        
        // 更新壓縮圖片UI
        function updateCompressedImageUI() {
            if (!compressedImageData) return;
            
            compressedImage.src = compressedImageData.base64;
            compressedImage.classList.remove('hidden');
            compressedPlaceholder.classList.add('hidden');
            compressedDimensions.textContent = `${compressedImageData.width} × ${compressedImageData.height} 像素`;
            compressedSize.textContent = formatFileSize(compressedImageData.size);
            compressedFormat.textContent = compressedImageData.format.toUpperCase();
        }
        
        // 下載壓縮后的圖片
        function downloadCompressedImage() {
            if (!compressedImageData) return;
            
            const link = document.createElement('a');
            link.href = compressedImageData.base64;
            
            // 生成文件名
            const originalName = fileName.textContent.split('.').slice(0, -1).join('.');
            link.download = `${originalName}_compressed.${compressedImageData.format}`;
            
            document.body.appendChild(link);
            link.click();
            document.body.removeChild(link);
            
            showInfo('圖片已下載', 'info');
        }
        
        // 顯示/隱藏加載動畫
        function showLoading(show) {
            if (show) {
                loadingOverlay.classList.remove('hidden');
            } else {
                loadingOverlay.classList.add('hidden');
            }
        }
    </script>

</body></html>

結(jié)果如下:

到此這篇關(guān)于HTML+CSS+JS實(shí)現(xiàn)簡單照片壓縮工具的示例詳解的文章就介紹到這了,更多相關(guān)JS照片壓縮內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評論

同心县| 慈溪市| 长乐市| 东安县| 青川县| 隆子县| 康定县| 马关县| 苍溪县| 司法| 民乐县| 靖安县| 大厂| 黄山市| 霍州市| 兰坪| 乌兰察布市| 盐津县| 伽师县| 阳谷县| 布拖县| 冀州市| 天水市| 慈溪市| 酒泉市| 民和| 思南县| 尚志市| 黑河市| 维西| 枣阳市| 浦江县| 海口市| 湘阴县| 分宜县| 临猗县| 当雄县| 赣榆县| 聂荣县| 东乌| 丰宁|