【问题标题】:Resize image in the client side before upload上传前在客户端调整图像大小
【发布时间】:2018-09-20 09:54:36
【问题描述】:

是否有任何客户端脚本可以自动调整用户在输入文件中上传的图像大小,并用在同一输入中调整大小的新图像自动替换旧图像..我想这样做以将此图像发送到我的 php 模型之后.. 在此先感谢您的帮助。

 <!DOCTYPE HTML>
 <html>
 <head>
     <title>Untitled</title>
 </head>
 <body>
    <form action="model.php" method="post" enctype="multipart/form-data">
       <input type="file" name="image"/>
       <input type="submit" name="do" value="submit"/>
    </form>
 </body>
 </html>

<?php
$target_dir = "folder/";
$filename    = $_FILES["image"]["name"];
$basename    = basename($_FILES["image"]["name"]);
$target_file = $target_dir .$basename;
$imageFileType = strtolower(pathinfo($target_file,PATHINFO_EXTENSION));
$tmp         = $_FILES["image"]["tmp_name"];
if(move_uploaded_file($tmp,$target_file))
{
    echo'done!';
}
?>

【问题讨论】:

  • 为什么不在服务器中调整它的大小?如果用户没有调整图像大小并发送了一个大的怎么办?另外,您没有检查文件类型……这很危险,真的很危险。任何人都可以上传 PHP 文件并在您的服务器上执行。
  • Mehdi Bounya - 这是一个基本代码而不是完整代码..兄弟仔细阅读我的问题..ه 我希望当用户上传图像时,客户端中的脚本会自动调整图像大小并用自动调整大小的新图像替换旧图像
  • 兄弟我已经阅读了您的问题,如果用户决定不调整图像大小并发送完整尺寸?
  • 我所说的..用户可以上传例如一个图像在输入中有 20 兆像素..所以我需要一个脚本客户端可以自动调整这个图像的大小...调整大小的脚本图片不是用户你懂我吗兄弟
  • 兄弟,我需要它用于我的本地主机中的个人工作而不是网站

标签: javascript php jquery html


【解决方案1】:

这就是我将如何解决它......

// Used for creating a new FileList in a round-about way
function FileListItem(a) {
  a = [].slice.call(Array.isArray(a) ? a : arguments)
  for (var c, b = c = a.length, d = !0; b-- && d;) d = a[b] instanceof File
  if (!d) throw new TypeError("expected argument to FileList is File or array of File objects")
  for (b = (new ClipboardEvent("")).clipboardData || new DataTransfer; c--;) b.items.add(a[c])
  return b.files
}

fileInput.onchange = async function change() {
  const maxWidth = 320
  const maxHeight = 240
  const result = []
  
  for (const file of this.files) {
    const canvas = document.createElement('canvas')
    const ctx = canvas.getContext('2d')
    const img = await file.image()
    
    // native alternetive way (don't take care of exif rotation)
    // https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/createImageBitmap
    // const img = await createImageBitmap(file)
    
    // calculate new size
    const ratio = Math.min(maxWidth / img.width, maxHeight / img.height)
    const width = img.width * ratio + .5 | 0
    const height = img.height * ratio + .5 | 0

    // resize the canvas to the new dimensions
    canvas.width = width
    canvas.height = height

    // scale & draw the image onto the canvas
    ctx.drawImage(img, 0, 0, width, height)
    
    // just to preview
    document.body.appendChild(canvas)

    // Get the binary (aka blob)
    const blob = await new Promise(rs => canvas.toBlob(rs, 1))
    const resizedFile = new File([blob], file.name, file)
    result.push(resizedFile)
  }
  
  const fileList = new FileListItem(result)
  
  // temporary remove event listener since
  // assigning a new filelist to the input
  // will trigger a new change event...
  fileInput.onchange = null
  fileInput.files = fileList
  fileInput.onchange = change
}
<!-- screw-filereader will take care of exif rotation for u -->
<script src="https://cdn.jsdelivr.net/npm/screw-filereader@1.4.3/index.min.js"></script>

<form action="https://httpbin.org/post" method="post" enctype="multipart/form-data">
  <input type="file" id="fileInput" name="image" accept="image/*" />
  <input type="submit" name="do" value="submit" />
</form>

PS。由于 iframe 更加沙盒和安全,它不会在 stackoverflow 中调整大小,在 jsfiddle 中工作:https://jsfiddle.net/f2oungs3/3/

【讨论】:

  • 感谢您的出色回答,我该如何为多个值执行此操作??
  • 更新了我的示例以使用和不使用 multiple 属性
【解决方案2】:

您可以通过 FileReader API 将图像绘制到调整大小的画布上,然后使用 canvas.toDataURL('image/png') 获取 base64 图像以发送到服务器。

以下是将图像大小调整为 320x240 的简化示例:

document.getElementById('example').addEventListener('change', function(e) {


	var canvas = document.createElement('canvas')
	var canvasContext = canvas.getContext('2d')
	canvas.setAttribute("style", 'opacity:0;position:absolute;z-index:-1;top: -100000000;left:-1000000000;width:320px;height:240px;')
  document.body.appendChild(canvas);
  
  var img = new Image;
  img.onload = function() {
      canvasContext.drawImage(img, 0, 0, 320, 240);
    	var base64Image = canvas.toDataURL('image/png')
      console.log(base64Image)
      // Post to server
      // sendImage(base64Image)
      
      document.body.removeChild(canvas)
    	URL.revokeObjectURL(img.src)
  }
	img.src = URL.createObjectURL(e.target.files[0]);
})

function sendImage() {
    var data = canvas.toDataURL('image/png');
    var ajax = null;
    if (window.XMLHttpRequest) {
        ajax = new XMLHttpRequest();
    } else if (window.ActiveXObject) {
        ajax = new ActiveXObject("Microsoft.XMLHTTP");
    }

    ajax.open('POST', 'https://example/route', true);
    ajax.setRequestHeader('Content-Type', 'application/octet-stream');
    ajax.onreadystatechange = function() {
        if (ajax.readyState === XMLHttpRequest.DONE) {
            if (ajax.status === 200) {
                // Success
            } else {
                // Fail
            }
        }
    };

    ajax.send(data);
}
&lt;input id="example" type="file" /&gt;

然后在服务器上:

// or however you want to get the posted contents.
$png = isset($GLOBALS["HTTP_RAW_POST_DATA"]) ? $GLOBALS["HTTP_RAW_POST_DATA"] : file_get_contents("php://input");
if (strpos($png, 'data:image/png;base64,') === 0) {
$png = str_replace('data:image/png;base64,', '', $png);
$png = str_replace(' ', '+', $png);
$png = base64_decode($png);
}

file_put_contents($image_path, $png);

编辑
该代码现在包含一种将图像上传到服务器的方法。
您还可以使用 jQuery 或更现代的 fetch API 来上传图像。 JsFiddle available here

【讨论】:

  • 它可以工作,但您将裁剪图像而不是调整它的大小。
  • 是的,这将裁剪而不是调整大小
猜你喜欢
  • 2016-01-15
  • 2013-11-29
  • 1970-01-01
  • 1970-01-01
  • 2017-10-30
  • 2015-09-22
  • 2010-09-30
  • 2013-12-30
  • 2014-11-29
相关资源
最近更新 更多