我有一个允许用户上传图片的表单。用户提交表单后,我想在前端为每张图片生成一个缩略图,然后将其存储在服务器上。
出于安全原因,无法更改文件输入字段的值,那么如何将前端在 js 中生成的一些缩略图图像发送到服务器?
在表单提交之前,前端是否可以从输入文件字段中设置的图像生成缩略图?然后同时提交?
我有一个允许用户上传图片的表单。用户提交表单后,我想在前端为每张图片生成一个缩略图,然后将其存储在服务器上。
出于安全原因,无法更改文件输入字段的值,那么如何将前端在 js 中生成的一些缩略图图像发送到服务器?
在表单提交之前,前端是否可以从输入文件字段中设置的图像生成缩略图?然后同时提交?
我发现这个更简单但功能强大的教程。它只是创建一个img
元素,并使用 fileReader 对象,将其源属性分配为表单输入的值
function previewFile() {
var preview = document.querySelector('img');
var file = document.querySelector('input[type=file]').files[0];
var reader = new FileReader();
reader.onloadend = function () {
preview.src = reader.result;
}
if (file) {
reader.readAsDataURL(file);
} else {
preview.src = "";
}
}
<input type="file" onchange="previewFile()"><br>
<img src="" height="200" alt="Image preview...">
在网上更好地搜索后,我找到了我的问题的答案。
可以将画布与File API结合在一起。
尝试上传下面演示中的任何图片,并看到新生成的缩略图会出现在表单的右侧。
演示: http : //jsfiddle.net/a_incarnati/fua75hpv/
function handleImage(e){
var reader = new FileReader();
reader.onload = function(event){
var img = new Image();
img.onload = function(){
canvas.width = img.width;
canvas.height = img.height;
ctx.drawImage(img,0,0);
}
img.src = event.target.result;
}
reader.readAsDataURL(e.target.files[0]);
}
DerekR 对这个问题给出了很好的回答:
建立在 Allesandro 写的更务实的东西之上。
该函数从 File API 获取一个文件,并尝试将其放入 boundBox 中,同时保留纵横比。没有绘制任何内容,但您会返回一个Promise
吐出生成的 dataUrl 的数据。
// Creates a thumbnail fitted insize the boundBox (w x h)
generateThumbnail(file, boundBox){
if (!boundBox || boundBox.length != 2){
throw "You need to give the boundBox"
}
var scaleRatio = Math.min(...boundBox) / Math.max(file.width, file.height)
var reader = new FileReader();
var canvas = document.createElement("canvas")
var ctx = canvas.getContext('2d');
return new Promise((resolve, reject) => {
reader.onload = function(event){
var img = new Image();
img.onload = function(){
var scaleRatio = Math.min(...boundBox) / Math.max(img.width, img.height)
let w = img.width*scaleRatio
let h = img.height*scaleRatio
canvas.width = w;
canvas.height = h;
ctx.drawImage(img, 0, 0, w, h);
return resolve(canvas.toDataURL(file.type))
}
img.src = event.target.result;
}
reader.readAsDataURL(file);
})
}
它可以像下面一样使用
generateThumbnail(file, [300, 300]).then(function(dataUrl){
console.log(dataUrl)
})
TL;DR:见 JSFiddle
因为我想通过 API 上传图像并显示图像的预览(两件事实际上非常适合彼此),所以我想出了这个:
(function(angular) {
angular
.module('app')
.directive('inputFilePreview', [function() {
var canvas, mapToModel, elementScope;
/**
* To be fired when the image has been loaded
*/
var imageOnLoad = function(){
canvas.width = this.width;
canvas.height = this.height;
canvas.getContext("2d").drawImage(this,0,0);
};
/**
* To be fired when the FileReader has loaded
* @param loadEvent {{}}
*/
var readerOnLoad = function(loadEvent){
var img = new Image();
img.onload = imageOnLoad;
img.src = loadEvent.target.result;
if(mapToModel) {
setModelValue(elementScope, mapToModel, img.src);
}
};
/**
* This allows us to set the value of a model in the scope of the element (or global scope if the
* model is an object)
* @param scope {{}}
* @param modelReference {string}
* @param value {*}
*/
var setModelValue = function(scope, modelReference, value) {
// If the model reference refers to the propery of an object (eg. "object.property")
if(~modelReference.indexOf('.')) {
var parts = modelReference.split('.', 2);
// Only set the value if that object already exists
if(scope.hasOwnProperty(parts[0])) {
scope[parts[0]][parts[1]] = value;
return;
}
}
scope[modelReference] = value;
};
/**
* The logic for our directive
* @param scope {{}}
* @param element {{}}
* @param attributes {{}}
*/
var link = function(scope, element, attributes) {
elementScope = scope;
canvas = document.getElementById(attributes.inputFilePreview);
if(attributes.hasOwnProperty('mapToModel')) {
mapToModel = attributes.mapToModel;
}
element.on('change', function(changeEvent) {
var reader = new FileReader();
reader.onload = readerOnLoad;
reader.readAsDataURL(changeEvent.target.files[0]);
});
};
return {
restrict: 'A',
link: link
};
}]);
})(angular);
预览工作所需的两个元素是:
<canvas id="image-preview"></canvas>
<input type="file" data-input-file-preview="image-preview" data-map-to-model="image.file" />
片段如下:
认为可能值得添加一个更现代的答案并引用MDN Web Docs。
您可以在输入元素上为“更改”添加一个事件侦听器,然后通过访问文件列表来this.files
显示所选图像的缩略图(如 MDN 示例中所示)。这是我最近的一个实现。上传水印是一个<input type="file></input>
uploadWatermark.addEventListener('change', function(){
const file = this.files[0];
if (file.type.startsWith('image/')) {
const img = document.createElement('img');
const watermarkPreview = document.getElementById("uploaded-watermark");
img.classList.add("prev-thumb");
img.file = file;
watermarkPreview.appendChild(img);
const reader = new FileReader();
reader.onload = (function(aImg) { return function(e) { aImg.src = e.target.result; }})(img);
reader.readAsDataURL(file);
}
});