source

입력 타입="파일"에 이미지를 추가해 같은 형태로 송신한 후 섬네일 이미지를 생성하는 방법

ittop 2023. 3. 13. 20:52
반응형

입력 타입="파일"에 이미지를 추가해 같은 형태로 송신한 후 섬네일 이미지를 생성하는 방법

저는 사용자가 사진을 업로드 할 수 있는 폼을 가지고 있습니다.유저가 폼을 송신하면, 프런트 엔드에 각 사진의 섬네일을 생성해, 서버에 보존하고 싶다고 생각하고 있습니다.

보안상의 이유로 파일 입력 필드의 값을 변경할 수 없습니다.프런트 엔드에 생성된 섬네일 이미지를 js 단위로 서버에 보내려면 어떻게 해야 합니까?

양식을 제출하기 전에 입력 파일 필드에 설정된 이미지에서 썸네일을 프런트 엔드로 생성할 수 있습니까?그리고 동시에 둘 다 제출하는 건가요?

간단하면서도 강력한 튜토리얼을 발견했습니다.단순히 데이터 전송에 대한imgfileReader 객체를 사용하여 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...">

온라인으로 더 잘 검색한 후에 나는 내 질문에 대한 답을 찾았다.

파일 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의 좋은 답변은 다음과 같습니다.

HTML5 캔버스에 이미지를 업로드하는 방법

알레산드로가 쓴 글 위에 좀 더 실용적인 걸 쓰죠

이 함수는 파일 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)
})

좀 더 현대적인 답변을 추가하고 MDN Web Docs를 인용할 가치가 있다고 생각했습니다.

입력 요소에 "변경"을 위한 이벤트청취자를 추가한 다음 파일 목록에 액세스하여 선택한 이미지의 축소판 그림을 표시할 수 있습니다.this.files(MDN의 예에 나타나 있습니다).이것이 나의 최근 구현입니다.upload Watermark는<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);
  }
  
});

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

스니펫은 다음과 같습니다.

(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>

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>

주의.

URL.createObjectUrl()은 메모리 누수의 원인이 될 수 있으므로 URL을 사용한 후 URL.revokeObjectURL()로 메모리를 해제해야 합니다.

언급URL : https://stackoverflow.com/questions/16500848/how-to-generate-a-thumbnail-image-after-adding-an-image-inside-an-input-type-fi

반응형