简体   繁体   English

如何在表单中的 input type="file" 中添加图像并在同一表单上提交它们后生成缩略图

[英]How to generate a thumbnail image after adding an image inside an input type="file" in a form and submitting them both on the same form

I have a form which allows the user to upload a picture.我有一个允许用户上传图片的表单。 After the user has submitted the form, I'd like to generate on the front-end a thumbnail for each picture and then store it on server.用户提交表单后,我想在前端为每张图片生成一个缩略图,然后将其存储在服务器上。

For security reason it's not possible to alter the value of a file input field, so how could I send to server some thumbnails images generated on the front-end in js?出于安全原因,无法更改文件输入字段的值,那么我如何向服务器发送一些在 js 前端生成的缩略图图像?

Is it possible on front-end to generate a thumbnail from the image set in the input file field before form submit?在提交表单之前,前端是否可以从输入文件字段中设置的图像生成缩略图? And then submitting both at same time?然后同时提交?

I found This simpler yet powerful tutorial .我发现这个更简单但功能强大的教程 It simply creates an img element and, using the fileReader object, assigns its source attribute as the value of the form input它只是创建一个img元素,并使用 fileReader 对象,将其 source 属性分配为表单输入的值

 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...">

After a better search online I found the answer to my question.在网上更好地搜索后,我找到了我的问题的答案。

It is possible to combine canvas together with the File API .可以将canvasFile API结合在一起。

Try to upload any picture in the demo below and see that a new generated thumbnail will appear on the right side of the form.尝试上传下面演示中的任何图片,并看到新生成的缩略图会出现在表单的右侧。

DEMO: http://jsfiddle.net/a_incarnati/fua75hpv/演示: 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]);     
}

A good answer has been given by DerekR to this question: DerekR 对这个问题给出了很好的答案:

How to upload image into HTML5 canvas 如何将图像上传到 HTML5 画布

Building on top of what Allesandro wrote to something more pragmatic.建立在 Allesandro 写的更务实的东西之上。

The function takes a file from the File API and tries to fit it in the boundBox while preserving the aspect ratio.该函数从 File API 获取一个文件,并尝试将其放入 boundBox 中,同时保留纵横比。 Nothing is drawn, but instead you get back a Promise that spits the dataUrl generated.没有绘制任何内容,但您会返回一个Promise ,该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);
  })
}

It can be used like below它可以像下面一样使用

generateThumbnail(file, [300, 300]).then(function(dataUrl){
    console.log(dataUrl)
})

TL;DR: See the JSFiddle TL;DR:见 JSFiddle

As I wanted to upload images via an API and show a preview of the image (two things that actually lended themselves well to each other), I came up with this:因为我想通过 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);

The two elements needed for the preview to work are:预览工作所需的两个元素是:

<canvas id="image-preview"></canvas>
<input type="file" data-input-file-preview="image-preview" data-map-to-model="image.file" />

Snippet Follows:片段如下:

 (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 }; }]) .controller('UploadImageController', [ '$scope', function ($scope) { $scope.image = { title: 'Test title' }; $scope.send = function (data) { $scope.sentData = JSON.stringify(data, null, 2); return false; }; }]); })(angular);
 canvas { max-height: 300px; max-width: 300px; }
 <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script> <form data-ng-app="app" data-ng-controller="UploadImageController"> <input data-ng-model="image.title" /> <br /> <canvas id="image-preview"></canvas> <br /> <input type="file" data-input-file-preview="image-preview" data-map-to-model="image.file" /> <br /> <input type="submit" data-ng-click="send(image)" /> <pre>{{sentData}}</pre> </form>

Thought it might be worth adding a more contemporary answer and citing MDN Web Docs .认为可能值得添加一个更现代的答案并引用MDN Web Docs

You can add an event listener for "change" on the input element and then show a thumbnail of the selected image by accessing the file list through this.files (as shown in an MDN examples).您可以在输入元素上为“更改”添加一个事件侦听器,然后通过this.files访问文件列表来显示所选图像的缩略图(如 MDN 示例中所示)。 Here is a recent implementation of mine.这是我最近的一个实现。 uploadWatermark is an <input type="file></input> uploadWatermark 是一个<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); } });

You can achieve it with URL.createObjectUrl() .您可以使用URL.createObjectUrl()来实现它。

  const handleImage = (e) => {
    const file = e.target.files[0]
    const url = URL.createObjectURL(file)

    return url
  }

  const addBackground = (url) => {
    document.querySelector('.wrapper').style.background = `url("${url}")`;
  }

<div className='wrapper'></div>

Caution警告

URL.createObjectUrl() can cause memory leak, so you have to release it by URL.revokeObjectURL() after using url. URL.createObjectUrl()会导致memory泄露,所以使用url后需要通过URL.revokeObjectURL()释放。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 HTML input type=file,提交表单前获取图片 - HTML input type=file, get the image before submitting the form jQuery通过表单输入type =“ file”提交后检测插入的图像 - JQuery detect inserted image after submitting through form input type=“file” 清除iOS 6 <input type=file> 图片缩图 - Clear iOS 6 <input type=file> image thumbnail 如何在一种形式(提交后)中将值(在文本字段中)显示为另一种形式(两者都在同一页面上) - how to display a value(in text field) from one form(after submitting it) to another form (both are on the same page) 如何从输入类型文件生成缩略图和文件名并将其插入到多个元素中? - How to generate thumbnail and file name from input type file and insert them in multiple element? 如何从缩略图图像中去除不透明度 - How to remove opacity form a thumbnail image 提交表单之前如何加载图像 - how to load image before submitting the form 表格是在输入类型=文件中没有选择文件的提交时间 - Form is timeouting on submitting without selected file in input type=file Redux表单:提交前如何在Redux表单中添加图片网址? - Redux Form: How to add an image url to Redux Form before submitting it? 提交带有鸟舍编辑图像的表单 - Submitting a form with an aviary edited image
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM