You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用FileReader在PHP上传前批量压缩图片

嘿Marco,我刚好折腾过一模一样的需求——相机拍的图太大,移动网传不动,要在客户端压缩后再用现有PHP脚本上传。给你一套能直接嵌进你现有代码的方案,步骤很清晰:

第一步:写一个客户端图片压缩函数

核心就是用FileReader读取图片,再通过Canvas缩放绘制,最后转成压缩后的Blob/File对象。这个函数可以直接复用:

function compressImage(file, maxWidth = 1920, maxHeight = 1080, quality = 0.7) {
  return new Promise((resolve, reject) => {
    const reader = new FileReader();
    
    reader.onload = function(e) {
      const img = new Image();
      img.src = e.target.result;
      
      img.onload = function() {
        // 计算缩放比例,保证图片不超过设定的最大尺寸
        let width = img.width;
        let height = img.height;
        if (width > maxWidth || height > maxHeight) {
          const ratio = Math.min(maxWidth / width, maxHeight / height);
          width *= ratio;
          height *= ratio;
        }
        
        // 创建Canvas绘制压缩后的图片
        const canvas = document.createElement('canvas');
        canvas.width = width;
        canvas.height = height;
        const ctx = canvas.getContext('2d');
        ctx.drawImage(img, 0, 0, width, height);
        
        // 转成Blob并包装成File对象(保留原文件名)
        canvas.toBlob(function(blob) {
          const compressedFile = new File([blob], file.name, { type: 'image/jpeg' });
          resolve(compressedFile);
        }, 'image/jpeg', quality);
      };
      
      img.onerror = () => reject('图片加载失败');
    };
    
    reader.onerror = () => reject('文件读取失败');
    reader.readAsDataURL(file);
  });
}
第二步:把压缩逻辑整合到你的现有上传流程里

你原来的JS应该有监听文件选择、预览、准备上传的代码,只需要修改文件处理部分,先压缩再走原有逻辑:

// 假设你的文件输入框选择器是你现有代码里的,这里按需调整
document.querySelectorAll('.upload-input').forEach(input => {
  input.addEventListener('change', async function(e) {
    const selectedFiles = Array.from(this.files);
    
    // 只压缩图片文件,非图片直接跳过
    const compressedFiles = await Promise.all(
      selectedFiles.map(file => {
        if (!file.type.startsWith('image/')) return file;
        return compressImage(file); // 这里可以传自定义参数,比如compressImage(file, 1280, 720, 0.6)
      })
    );
    
    // ----------------------
    // 这里放你原有的预览逻辑
    // 比如用URL.createObjectURL(compressedFile)生成预览图地址
    // ----------------------
    
    // 准备FormData,格式和你原有上传完全一致
    const formData = new FormData();
    // 注意:这里的name要和你PHP后端接收的字段名完全匹配,比如你原来用的是`files[]`
    compressedFiles.forEach(file => {
      formData.append('files[]', file);
    });
    
    // ----------------------
    // 这里放你原有的AJAX上传代码
    // 比如用fetch或者XMLHttpRequest发送formData到你的PHP脚本
    // ----------------------
  });
});
第三步:PHP后端几乎不用改

因为压缩后的文件还是标准的File对象,FormData的格式和你原来的上传请求完全一样,所以你现有的PHP接收代码直接能用。举个典型的例子(和你现有代码逻辑对齐):

<?php
$uploadDir = 'uploads/';
if (!is_dir($uploadDir)) mkdir($uploadDir, 0755, true);

$uploaded = [];
if (isset($_FILES['files'])) {
  foreach ($_FILES['files']['tmp_name'] as $key => $tmpPath) {
    $fileName = basename($_FILES['files']['name'][$key]);
    $savePath = $uploadDir . uniqid() . '-' . $fileName;
    
    if (move_uploaded_file($tmpPath, $savePath)) {
      $uploaded[] = $savePath;
    }
  }
}

echo json_encode(['success' => true, 'files' => $uploaded]);
?>
几个小细节提醒
  • 压缩参数可以按需调:quality是0-1的数值,越小压缩率越高;maxWidth/maxHeight可以设成你能接受的最大尺寸;
  • 如果要处理PNG透明图,把canvas.toBlob里的image/jpeg改成image/png就行,但PNG压缩率不如JPEG;
  • 记得加错误捕获:比如Promise.all后面加.catch(err => console.error('压缩失败:', err)),避免用户上传出错没反馈;
  • 动态添加上传字段的话,要给新创建的input也绑定上面的change事件监听。

内容的提问来源于stack exchange,提问作者Marco

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.19 10:38:39