【发布时间】:2021-08-04 23:19:33
【问题描述】:
我正在尝试在一些低带宽设备上使用 JavaScript 在客户端压缩图像,但我目前使用 HTML5 文件 API 陷入困境。我是新手,如果我遗漏了一些重要的东西,请多多包涵。
我有一些输入标签,理想情况下应该打开移动相机,捕获单个图像,压缩并将文件发送到后端。虽然这可以通过启用多个上传的单个输入字段来完成,但我需要多个图像字段来根据某些类别隔离图像。
输入框如下:
<input type="file" name="file1" id="file1" capture="camera" accept="image/*">
<input type="file" name="file2" id="file2" capture="camera" accept="image/*">...
这是图像压缩逻辑:
// Takes upload element id ("file1") and a maxSize to resize, ideally on a change event
window.resizePhotos = function(id, maxSize){
var file = document.getElementById(id).files[0];
// Ensuring it's an image
if(file.type.match(/image.*/)) {
// Loading the image
var reader = new FileReader();
reader.onload = function (readerEvent) {
var image = new Image();
image.onload = function (imageEvent) {
// Resizing the image and keeping its aspect ratio
var canvas = document.createElement("canvas"),
max_size = maxSize,
width = image.width,
height = image.height;
if (width > height) {
if (width > max_size) {
height *= max_size / width;
width = max_size;
}
} else {
if (height > max_size) {
width *= max_size / height;
height = max_size;
}
}
canvas.width = width;
canvas.height = height;
canvas.getContext("2d").drawImage(image, 0, 0, width, height);
var dataUrl = canvas.toDataURL("image/jpeg");
var resizedImage = dataURLToBlob(dataUrl);
$.event.trigger({
type: "imageResized",
blob: resizedImage,
url: dataUrl
});
}
image.src = readerEvent.target.result;
}
reader.readAsDataURL(file);
}
};
// Function to convert a canvas to a BLOB
var dataURLToBlob = function(dataURL) {
var BASE64_MARKER = ';base64,';
if (dataURL.indexOf(BASE64_MARKER) == -1) {
var parts = dataURL.split(',');
var contentType = parts[0].split(':')[1];
var raw = parts[1];
return new Blob([raw], {type: contentType});
}
var parts = dataURL.split(BASE64_MARKER);
var contentType = parts[0].split(':')[1];
var raw = window.atob(parts[1]);
var rawLength = raw.length;
var uInt8Array = new Uint8Array(rawLength);
for (var i = 0; i < rawLength; ++i) {
uInt8Array[i] = raw.charCodeAt(i);
}
return new Blob([uInt8Array], {type: contentType});
}
// Handling image resized events
$(document).on("imageResized", function (event) {
if (event.blob && event.url) {
document.getElementById('file1').files[0] = event.url; // --> Tried this, did not work
document.getElementById('file1').files[0].value = (URL || webkitURL).createObjectURL(event.blob); // --> Tried doing this looking at some other answers but did not work
console.log(document.getElementById('file1').files[0]); // Original file is loading fine
console.log(event.url); // Image compression is working correctly and producing the base64 data
}
});
$(window).on("load", function() {
// Resets the value to when navigating away from the page and choosing to upload the same file (extra feature)
$("#file1").on("click touchstart" , function(){
$(this).val("");
});
// Action triggers when user has selected any file
$("#file1").change(function(e) {
resizePhotos("file1", 1024)
});
});
在 PHP 脚本中,我通常会尝试从 POST 请求中捕获文件,例如:
$file1 = $_FILES["file1"]["tmp_name"];
$file2 = $_FILES["file2"]["tmp_name"];
...
但这不起作用,因为它在 tmp 目录中查找原始用户选择的文件(例如,在我的情况下,实际的临时文件是 C:\xampp\tmp\php25CB.tmp )
我尝试过的一件事是将输入字段放在表单标签之外,使用按钮启用点击行为,并在表单中使用修改后的数据创建新的输入字段,例如:
var newinput = document.createElement("input");
newinput.type = 'file';
newinput.name = 'file1';
newinput.files[0] = event.url;
document.getElementById('parentdiv').appendChild(newinput);
不用说,这没有任何效果,PHP脚本无法识别任何文件。
请指导我并建议 JavaScript/PHP 脚本中所需的任何更改,以便我可以接受修改后的文件,而不是输入字段中原始用户上传的文件。
【问题讨论】:
-
Fyi,canvas 的压缩率非常差,它可以将压缩良好的图像增加很多:让我们拿我的 gravatar 图像,不做任何更改,看看会发生什么:jsfiddle.net/0mfg8vbk 剧透:尺寸增加了 2.33%
标签: javascript php html image file