前几天填写备案资料时需要上传营业执照,要求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 编辑过