前几天填写备案资料时需要上传营业执照,要求2MB以内,老板发给我的文件有十几MB,无法上传,用网上的在线工具,又担心安全性。以前也经常遇到需要图片太大的问题,基本上都是找别人用vip办公软件处理的,每次都要麻烦别人,于是我就想着自己做一个,使用方便还安全。接下来我给大家介绍一下我的图片压缩工具,源码在结尾。

使用说明
先体验一下吧!
👉https://www.codeobservatory.cn/tools/image-compress.html
支持格式
JPEG (.jpg, .jpeg)
PNG (.png)
GIF (.gif)
WebP (.webp)
BMP (.bmp)
自定义压缩质量
使用滑块自由调整压缩质量(0%-100%)
0% - 最高压缩(最小文件尺寸,最低质量)
100% - 最低压缩(最大文件尺寸,最高质量)
默认值设置为30% - 良好平衡点
实时显示压缩质量百分比
技术实现
源码如下
话不多说,直接开干!
<div class="container"> <header> <h1><i class="fas fa-file-image"></i> 免费在线图片压缩工具</h1> <p>保持画质清晰,快速缩小JPG/PNG/GIF/WebP文件,自定义压缩大小,压缩后可直接下载</p> </header>
<div class="content"> <div class="upload-section"> <h2 class="section-title"><i class="fas fa-cloud-upload-alt"></i> 上传图片</h2> <a href="/" class="browse-btn refresh" target="_blank" title="码农观测站">首页</a> <button class="browse-btn refresh" onclick="window.location.reload();">刷新</button> <div class="upload-area" id="uploadArea"> <i class="fas fa-images"></i> <h3>拖放图片到此处</h3> <p>支持 JPG, PNG, GIF, WEBP 格式</p> <button class="browse-btn">选择图片</button> <input type="file" id="fileInput" class="file-input" accept="image/*"> </div>
<div class="preview-container"> <div class="preview-title"><i class="fas fa-eye"></i> 图片预览</div> <div class="image-preview" id="imagePreview"> <img id="previewImage" src="" alt="预览图"> </div>
<div class="compression-control"> <div class="quality-label"> <span>压缩质量:</span> <span class="quality-value" id="qualityValue">30%</span> </div> <div class="slider-container"> <input type="range" min="0" max="100" value="30" class="quality-slider" id="qualitySlider"> </div> <div class="slider-ticks"> <span>0%</span> <span>25%</span> <span>50%</span> <span>75%</span> <span>100%</span> </div> </div>
<div class="progress-container" id="progressContainer"> <div class="progress-bar" id="progressBar"></div> </div>
<button class="upload-btn" id="uploadBtn" disabled="">上传并压缩图片</button>
<div class="api-info"> </div> </div> </div>
<div class="result-section"> <h2 class="section-title"><i class="fas fa-download"></i> 压缩结果</h2>
<div class="result-container"> <div class="result-content"> <div class="result-placeholder" id="resultPlaceholder"> <i class="fas fa-cloud-download-alt"></i> <p>图片压缩后将显示在这里</p> <p>您可以直接下载压缩后的图片</p> </div>
<img id="compressedImage" class="compressed-image" src="" alt="压缩后的图片"> <a id="downloadLink" class="download-btn"> <i class="fas fa-download"></i> 下载压缩图片 </a> </div>
<div class="response-area"> <h3 class="response-title"><i class="fas fa-comment-alt"></i> 处理状态</h3> <div class="response-content" id="responseContent"> 等待上传图片... </div> </div> </div>
<div class="info-card"> <h4><i class="fas fa-info-circle"></i> 使用说明</h4> <ul> <li>上传图片后,通过滑块调整压缩质量(0%-100%)</li> <li>点击"上传并压缩图片"按钮进行处理</li> <li>压缩完成后,右侧会显示压缩后的图片</li> <li>点击"下载压缩图片"按钮保存结果</li> </ul> </div> </div> </div>
<footer> <p>免费在线图片压缩工具 © 2025 | <a href="https://www.codeobservatory.cn" target="_blank" title="码农观测站">码农观测站</a></p> </footer> </div>
* { margin: 0; padding: 0; box-sizing: border-box; font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;}
body { background: linear-gradient(135deg, #1e3c72 0%, #2a5298 100%); min-height: 100vh; display: flex; justify-content: center; align-items: center; padding: 20px;}
.container { width: 100%; max-width: 1200px; background-color: rgba(255, 255, 255, 0.97); border-radius: 20px; box-shadow: 0 20px 50px rgba(0, 0, 0, 0.3); overflow: hidden; display: flex; flex-direction: column;}
header { background: linear-gradient(to right, #1a2980, #26d0ce); color: white; padding: 30px 40px; text-align: center; position: relative; overflow: hidden;}
header::before { content: ""; position: absolute; top: -50%; left: -50%; width: 200%; height: 200%; background: radial-gradient(circle, rgba(255,255,255,0.15) 0%, transparent 70%); transform: rotate(30deg); }
header h1 { font-size: 2.5rem; margin-bottom: 10px; display: flex; align-items: center; justify-content: center; gap: 15px; position: relative; text-shadow: 0 2px 4px rgba(0,0,0,0.2); }
header p { font-size: 1.2rem; opacity: 0.9; max-width: 700px; margin: 15px auto 0; position: relative; }
.content { display: flex; padding: 0; flex-wrap: wrap;}
.upload-section { flex: 1; min-width: 350px; padding: 40px; border-right: 1px solid #eee; position: relative;}
.result-section { flex: 1; min-width: 350px; padding: 40px; background-color: #f9f9ff; display: flex; flex-direction: column;}
.section-title { font-size: 1.6rem; color: #333; margin-bottom: 25px; display: flex; align-items: center; gap: 10px; position: relative; padding-bottom: 10px;}
.section-title::after { content: ""; position: absolute; bottom: 0; left: 0; width: 50px; height: 3px; background: linear-gradient(to right, #1a2980, #26d0ce); border-radius: 3px; }
.section-title i { color: #1a2980; }
.upload-area { border: 3px dashed #1a2980; border-radius: 15px; padding: 40px 20px; text-align: center; cursor: pointer; transition: all 0.3s; background-color: #f0f4ff; margin-bottom: 25px; position: relative; overflow: hidden;}
.upload-area:hover, .upload-area.dragover { background-color: #e6ebff; transform: translateY(-5px); box-shadow: 0 10px 25px rgba(26, 41, 128, 0.2); }
.upload-area i { font-size: 4.5rem; color: #1a2980; margin-bottom: 20px; opacity: 0.8; }
.upload-area h3 { font-size: 1.5rem; color: #444; margin-bottom: 15px; }
.upload-area p { color: #666; margin-bottom: 20px; font-size: 1.05rem; }
.browse-btn { background: linear-gradient(to right, #1a2980 0%, #26d0ce 100%); color: white; border: none; padding: 13px 35px; font-size: 1.1rem; border-radius: 50px; cursor: pointer; transition: all 0.3s; font-weight: 600; box-shadow: 0 5px 15px rgba(26, 41, 128, 0.3); position: relative; overflow: hidden;}
.browse-btn:hover { transform: translateY(-3px); box-shadow: 0 8px 20px rgba(26, 41, 128, 0.4); }
.browse-btn:active { transform: translateY(1px); }
.browse-btn.refresh { position: absolute; top: 40px; right: 40px; padding: 7px 25px; }
.file-input { display: none;}
.preview-container { margin-top: 30px; text-align: center;}
.preview-title { font-size: 1.3rem; margin-bottom: 20px; color: #555; display: flex; align-items: center; justify-content: center; gap: 10px;}
.image-preview { width: 100%; max-height: 220px; border-radius: 14px; overflow: hidden; box-shadow: 0 8px 20px rgba(0, 0, 0, 0.12); display: none; margin: 0 auto 25px; border: 1px solid #eee;}
.image-preview img { width: 100%; height: 100%; object-fit: contain; background: #f8f8f8; }
.compression-control { background: white; border-radius: 14px; padding: 20px; margin-bottom: 25px; box-shadow: 0 4px 15px rgba(0, 0, 0, 0.08);}
.quality-label { display: flex; justify-content: space-between; margin-bottom: 15px; font-size: 1.1rem; color: #444;}
.quality-value { font-weight: 700; color: #1a2980; font-size: 1.2rem; min-width: 45px; text-align: right;}
.slider-container { position: relative; height: 40px;}
.quality-slider { width: 100%; height: 10px; -webkit-appearance: none; background: linear-gradient(to right, #ff416c, #ff4b2b, #ff9500, #ffcc00, #a8e063, #56ab2f); outline: none; border-radius: 5px;}
.quality-slider::-webkit-slider-thumb { -webkit-appearance: none; width: 25px; height: 25px; border-radius: 50%; background: #1a2980; cursor: pointer; box-shadow: 0 2px 10px rgba(0,0,0,0.2); border: 3px solid white; }
.quality-slider::-moz-range-thumb { width: 25px; height: 25px; border-radius: 50%; background: #1a2980; cursor: pointer; box-shadow: 0 2px 10px rgba(0,0,0,0.2); border: 3px solid white; }
.slider-ticks { display: flex; justify-content: space-between; padding: 0 14px; font-size: 0.85rem; color: #777; margin-top: 5px;}
.upload-btn { width: 100%; padding: 16px; background: linear-gradient(to right, #00c853 0%, #64dd17 100%); color: white; border: none; border-radius: 14px; font-size: 1.2rem; font-weight: 600; cursor: pointer; transition: all 0.3s; box-shadow: 0 6px 18px rgba(0, 200, 83, 0.3); display: block; position: relative; overflow: hidden;}
.upload-btn:hover { transform: translateY(-3px); box-shadow: 0 9px 22px rgba(0, 200, 83, 0.4); }
.upload-btn:disabled { background: #cccccc; cursor: not-allowed; transform: none; box-shadow: none; }
.progress-container { height: 10px; background-color: #e0e0e0; border-radius: 5px; margin: 20px 0; overflow: hidden; display: none;}
.progress-bar { height: 100%; background: linear-gradient(to right, #1a2980 0%, #26d0ce 100%); width: 0%; transition: width 0.4s ease;}
.comparison-container { display: flex; justify-content: space-around; margin: 25px 0; gap: 20px;}
.comparison-item { text-align: center; flex: 1; background: white; padding: 20px 15px; border-radius: 14px; box-shadow: 0 4px 14px rgba(0, 0, 0, 0.08);}
.comparison-item h4 { margin-bottom: 14px; color: #555; font-size: 1.15rem; }
.size-info { font-weight: 700; font-size: 1.3rem; color: #1a2980;}
.api-info { background: #e3f2fd; padding: 15px; border-radius: 10px; margin-top: 20px; font-family: monospace; font-size: 0.95rem; color: #1a2980;}
footer { text-align: center; padding: 25px; color: #666; background-color: #f5f5f5; border-top: 1px solid #eee; font-size: 1.05rem;}
.result-container { background: white; border-radius: 15px; padding: 25px; box-shadow: 0 7px 20px rgba(0, 0, 0, 0.07); min-height: 180px; border: 1px solid #f0f0f0; flex-grow: 1; display: flex; flex-direction: column;}
.result-content { flex-grow: 1; display: flex; flex-direction: column; justify-content: center; align-items: center;}
.compressed-image { max-width: 100%; max-height: 250px; border-radius: 14px; box-shadow: 0 5px 15px rgba(0,0,0,0.1); margin-bottom: 25px; border: 1px solid #eee; display: none;}
.download-btn { display: inline-block; background: linear-gradient(to right, #1a2980 0%, #26d0ce 100%); color: white; padding: 14px 30px; font-size: 1.1rem; font-weight: 600; border-radius: 50px; text-decoration: none; transition: all 0.3s; box-shadow: 0 5px 15px rgba(26, 41, 128, 0.3); display: none; align-items: center; gap: 10px;}
.download-btn:hover { transform: translateY(-3px); box-shadow: 0 8px 20px rgba(26, 41, 128, 0.4); }
.info-card { background: white; border-radius: 15px; padding: 25px; box-shadow: 0 7px 20px rgba(0, 0, 0, 0.07); margin-bottom: 30px; border: 1px solid #f0f0f0;}
.info-card h4 { color: #1a2980; margin-bottom: 20px; font-size: 1.3rem; display: flex; align-items: center; gap: 14px; }
.info-card ul { list-style-type: none; padding-left: 5px; }
.info-card li { margin-bottom: 14px; padding-left: 32px; position: relative; font-size: 1.05rem; color: #555; line-height: 1.5; }
.info-card li:before { content: "•"; color: #1a2980; font-size: 2rem; position: absolute; left: 0; top: -8px; }
.response-area { background: white; border-radius: 15px; padding: 25px; box-shadow: 0 7px 20px rgba(0, 0, 0, 0.07); min-height: 100px; border: 1px solid #f0f0f0; margin-top: 20px;}
.response-title { color: #1a2980; margin-bottom: 15px; font-size: 1.3rem; display: flex; align-items: center; gap: 14px;}
.response-content { font-size: 1.1rem; line-height: 1.6; color: #555; min-height: 60px; display: flex; align-items: center; justify-content: center; padding: 15px; text-align: center;}
@media (max-width: 768px) { body { padding:20px 0; } header { padding: 30px 20px; } .content { flex-direction: column; }
.upload-section { border-right: none; border-bottom: 1px solid #eee; padding:20px; } .result-section { padding:20px; } header h1 { font-size: 2rem; }
header p { font-size: 1rem; } .browse-btn.refresh { top:20px; right:20px; } a.browse-btn.refresh { right:130px; }}
.success-message { color: #00c853; font-weight: 600;}
.error-message { color: #f44336; font-weight: 600;}
.result-placeholder { text-align: center; color: #777; font-size: 1.1rem; padding: 40px 20px;}
.result-placeholder i { font-size: 4rem; color: #e0e0e0; margin-bottom: 20px; }
document.addEventListener('DOMContentLoaded', function () { const uploadArea = document.getElementById('uploadArea'); const fileInput = document.getElementById('fileInput'); const uploadBtn = document.getElementById('uploadBtn'); const imagePreview = document.getElementById('imagePreview'); const previewImage = document.getElementById('previewImage'); const responseContent = document.getElementById('responseContent'); const progressContainer = document.getElementById('progressContainer'); const progressBar = document.getElementById('progressBar'); const originalSize = document.getElementById('originalSize'); const compressedSize = document.getElementById('compressedSize'); const qualitySlider = document.getElementById('qualitySlider'); const qualityValue = document.getElementById('qualityValue'); const compressedImage = document.getElementById('compressedImage'); const downloadLink = document.getElementById('downloadLink'); const resultPlaceholder = document.getElementById('resultPlaceholder');
qualitySlider.addEventListener('input', function () { qualityValue.textContent = this.value + '%'; });
uploadArea.addEventListener('click', () => { fileInput.click(); });
['dragenter', 'dragover', 'dragleave', 'drop'].forEach(eventName => { uploadArea.addEventListener(eventName, preventDefaults, false); });
function preventDefaults(e) { e.preventDefault(); e.stopPropagation(); }
['dragenter', 'dragover'].forEach(eventName => { uploadArea.addEventListener(eventName, highlight, false); });
['dragleave', 'drop'].forEach(eventName => { uploadArea.addEventListener(eventName, unhighlight, false); });
function highlight() { uploadArea.classList.add('dragover'); }
function unhighlight() { uploadArea.classList.remove('dragover'); }
uploadArea.addEventListener('drop', handleDrop, false);
function handleDrop(e) { const dt = e.dataTransfer; const files = dt.files; if (files.length) { handleFiles(files); } }
fileInput.addEventListener('change', function () { if (this.files.length) { handleFiles(this.files); } });
function handleFiles(files) { const file = files[0]; if (!file.type.match('image.*')) { responseContent.innerHTML = '<span class="error-message">错误:请选择图片文件(JPG, PNG, GIF, WEBP)</span>'; return; }
compressedImage.style.display = 'none'; downloadLink.style.display = 'none'; resultPlaceholder.style.display = 'block';
const reader = new FileReader(); reader.onload = function (e) { previewImage.src = e.target.result; imagePreview.style.display = 'block'; uploadBtn.style.display = 'block'; uploadBtn.disabled = false; }; reader.readAsDataURL(file);
responseContent.innerHTML = '<span class="success-message">图片已选择,点击"上传并压缩图片"按钮开始处理...</span>'; }
uploadBtn.addEventListener('click', function () { if (!fileInput.files.length) return;
const file = fileInput.files[0]; const quality = parseInt(qualitySlider.value); const formData = new FormData(); formData.append('imageFile', file); formData.append('compressionQuality', quality);
progressContainer.style.display = 'block'; progressBar.style.width = '0%';
uploadBtn.disabled = true; uploadBtn.textContent = '处理中...'; uploadBtn.style.background = 'linear-gradient(to right, #ff9800 0%, #ff5722 100%)';
responseContent.innerHTML = '<span class="success-message">正在上传并压缩图片,请稍候...</span>';
const progressInterval = setInterval(() => { const currentWidth = parseInt(progressBar.style.width) || 0; if (currentWidth < 90) { progressBar.style.width = (currentWidth + 10) + '%'; } }, 300);
fetch('/api/yourapiname', { method: 'POST', body: formData }) .then(response => { debugger clearInterval(progressInterval); progressBar.style.width = '100%';
if (response.ok) { return response.blob(); } else if (response.status === 400) { return response.text().then(text => { throw new Error(text || '无效请求'); }); } else { throw new Error(`请求失败,状态码: ${response.status}`); } }) .then(blob => { const compressedUrl = URL.createObjectURL(blob);
compressedImage.src = compressedUrl; compressedImage.style.display = 'block';
downloadLink.href = compressedUrl; downloadLink.download = `compressed_${fileInput.files[0].name}`; downloadLink.style.display = 'inline-block';
resultPlaceholder.style.display = 'none';
setTimeout(() => { responseContent.innerHTML = '<span class="success-message">图片压缩成功!可下载压缩后的图片</span>'; uploadBtn.textContent = '上传成功!'; uploadBtn.style.background = 'linear-gradient(to right, #00c853 0%, #64dd17 100%)'; }, 500); }) .catch(error => { clearInterval(progressInterval); progressBar.style.backgroundColor = '#f44336'; responseContent.innerHTML = `<span class="error-message">错误: ${error.message}</span>`; uploadBtn.textContent = '上传失败,重试'; uploadBtn.disabled = false; uploadBtn.style.background = 'linear-gradient(to right, #f44336 0%, #e91e63 100%)'; }); });});
阅读原文:原文链接
该文章在 2025/7/18 11:09:54 编辑过