ユーザーが写真をアップロードできるフォームがあります。ユーザーがフォームを送信した後、フロントエンドで各写真のサムネイルを生成し、サーバーに保存したいと思います。
セキュリティ上の理由から、ファイル入力フィールドの値を変更することはできません。そこで、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...">
より良いオンライン検索の後、私は私の質問への答えを見つけました。
canvasと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から適切な回答が得られました。
TL; DR: JSFiddleを参照
APIを介して画像をアップロードし、画像のプレビューを表示したかったので(実際にお互いによく合った2つのこと)、私はこれを思いつきました:
(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);
プレビューが機能するために必要な2つの要素は次のとおりです。
<canvas id="image-preview"></canvas>
<input type="file" data-input-file-preview="image-preview" data-map-to-model="image.file" />
スニペットは次のとおりです:
(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>
より現代的な答えを追加し、 MDN Web Docs を引用する価値があるかもしれないと思った。
入力要素に「変更」のイベントリスナーを追加し、this.files
を介してファイルリストにアクセスすることで、選択した画像のサムネイルを表示できます(MDNの例に示すように)。これが私の最近の実装です。 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);
}
});