Обрезать изображение с помощью JavaScript

В моем приложении Angular 6 я делаю опцию загрузки файла, и в предварительном просмотре загруженный файл должен отображаться с автоматической обрезкой и автоматическим изменением размера.

Я пробовал следующее,

HTML:

<canvas id = "canvas"></canvas>
<div style = "display:none;">
  <img id = "source" [src] = "url" width = "300" height = "227">
</div>
<input type='file' (change) = "onSelectFile($event)">

Функция выбора файла:

  onSelectFile(event) {
    if (event.target.files && event.target.files[0]) {
      var reader = new FileReader();

      reader.readAsDataURL(event.target.files[0]); // read file as data url

      reader.onload = (event) => { // called once readAsDataURL is completed
        this.url = event.target.result;
      }

      const canvas : any =  document.getElementById('canvas');
      const ctx = canvas.getContext('2d');
      const image = document.getElementById('source');

      ctx.drawImage(image, 33, 71, 104, 124, 21, 20, 87, 104);
    }
  }

Выше я пробовал следующее со ссылкой на ссылку https://jsfiddle.net/8jwq3cs7/

      const canvas : any =  document.getElementById('canvas');
      const ctx = canvas.getContext('2d');
      const image = document.getElementById('source');

      ctx.drawImage(image, 33, 71, 104, 124, 21, 20, 87, 104);

Перед использованием холста исходное изображение выглядит так: https://mdn.mozillademos.org/files/5397/rhino.jpg

А после использования холста это так: https://jsfiddle.net/8jwq3cs7/

Но если я выберу образ из choose file, то после выбора я буду невозможно увидеть изображение ...

Рабочий пример:https://stackblitz.com/edit/angular-file-upload-preview-uwpf8f

Даже решение с одним только чистым JavaScript также было бы заметным, если бы не в Angular ...

Требование:, если я выберу файл, тогда тот же файл необходимо обрезать и автоматически подогнать под размер при предварительном просмотре ...

Пожалуйста, помогите мне добиться результата без jQuery или какой-либо библиотеки ...

Не забудьте реализовать коррекцию тега ориентации EXIF, чтобы исправить ориентацию мобильной фотографии.

Rik 17.12.2018 08:48

@ Rik, извини, я не могу тебя достать .. Пожалуйста, помогите мне обрезать и изменить размер выбранного изображения ..

Maniraj Murugan 17.12.2018 08:51

Вы хотите обрезать его до лица «животные» или только до определенного размера, например background-size: cover?

muuvmuuv 17.12.2018 10:12

@undefined Если ваш скрипт будет показывать превью изображений JPEG, они будут неправильно повернуты, если у них есть тег ориентации EXIF ​​(что имеет место, когда изображения сделаны на мобильных телефонах). Поэтому вам нужно будет прочитать тег и соответствующим образом повернуть контекст холста. medium.com/@Orangeeli/oh-my-exif-777335e26213

Rik 17.12.2018 10:20

Возможный дубликат Обрезка изображения и изменение размера

EJK 20.12.2018 04:47
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
17
6
62 771
5

Ответы 5

Вот функция для получения изображения при загрузке с помощью кнопки выбрать файл

function readURL() {
    const myimg = document.getElementById("myimg");
    const input = document.getElementById("myfile");
    if (input.files && input.files[0]) {
        const reader = new FileReader();
        reader.onload = e => {
            console.info("changed");
            myimg.src = e.target.result;
        };
        reader.readAsDataURL(input.files[0]);
    }
}
document.querySelector('#myfile').addEventListener('change', () => {
    readURL();
});

И HTML будет

<img src = "" id = "myimg"><br>
<input type = "file" id = "myfile">

Вот такой рабочая рабочий пример

Если вы добавите файл, изображение предварительного просмотра будет обновлено. Здесь вы действительно получаете URL-адрес данных. Используйте URL-адрес данных, чтобы загрузить изображение на холст, а затем обрезать его. звонок drawimg(e.target.result)

function drawimg(idata) {
    const img = new Image();
    img.onload = () => {
        ctx.drawImage(img, 33, 71, 104, 124, 21, 20, 87, 104);
    };
    img.src = idata;
}

См. Рабочий скрипт: здесь

Я просто использовал jquery, чтобы легко выполнять функцию .change (). В этом нет большого количества jquery. Просто прочтите перед тем, как проголосовать против

Geon George 17.12.2018 09:01

Здравствуйте, дорогой, это приложение angular, здесь мы ни в коем случае не будем использовать jquery, даже маленький или большой .. Использование jquery строго ограничено .. Если мне нужен jquery, я бы не стал публиковать этот вопрос ..

Maniraj Murugan 17.12.2018 09:03

@undefined сейчас отредактировал ответ. Вы даже не прочитали ответ должным образом, прежде чем проголосовали против. Код был и продолжает работать. Я использовал jquery только для идентификации события изменения файла. Теперь это полностью ванильный js

Geon George 17.12.2018 09:12

Думаю, вы не поняли мой вопрос .. Мне нужно обрезать загруженное изображение .. Прочтите внимательно ..

Maniraj Murugan 17.12.2018 09:15

Ваше заключительное предложение - «Используйте URL-адрес данных для загрузки изображения на холст, а затем обрежьте его» - это вопрос, который, похоже, задает OP; Можете ли вы расширить это, чтобы показать как, что может быть выполнено? Также не забывайте объяснять свои ответы, чтобы люди могли поучиться у вас.

David Thomas 17.12.2018 09:25

@undefined Вот полная рабочая версия: jsfiddle.net/geongeorgek/8jwq3cs7/14

Geon George 17.12.2018 09:32

@undefined К сожалению, изменение не было сохранено. Вот так: jsfiddle.net/geongeorgek/rp0bym1a

Geon George 17.12.2018 09:54

Итак, вы хотите, чтобы пользователь выбирал область лица или автоматически определял лица? в любом случае вы неправильно сформулировали вопрос или извините за неверное понимание

Geon George 17.12.2018 10:00

Вот как я реализовал это в моем случае:

  onSelectFile(event) {
    if (event.target.files && event.target.files[0]) {
      var reader = new FileReader();

      reader.readAsDataURL(event.target.files[0]); // read file as data url

      reader.onload = (event) => { // called once readAsDataURL is completed
       console.info(event);
        this.url = event.target.result;
        const canvas = document.getElementById('canvas');
        const ctx = canvas.getContext('2d');
        const image = new Image();
        image.src = this.url;

        ctx.drawImage(image, 33, 71, 104, 124, 21, 20, 87, 104);

      }

Рабочая демонстрация stackblitz находится здесь: https://stackblitz.com/edit/angular-file-upload-preview-qrrgx5

Надеюсь, это поможет, и это то, что вы хотите.

Мое требование должно быть таким: если я загружаю свое изображение с высотой 500 пикселей и шириной 500 пикселей, мне нужно изменить его размер, отображая только лицо с автоматическим кадрированием и автоматическим изменением размера. Надеюсь, вы поняли, что я загружаю изображение для изображение профиля, тогда оно автоматически обрезает только область лица и отображает ее .. Я ожидаю, что автоматическая обрезка области лица будет только в загружаемом нами изображении профиля ..

Maniraj Murugan 17.12.2018 10:47
<html>
    <head>
    <style>
    #preview {
    background: red;
    border: 1px solid green;
    }
    </style>
    <script src = "https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
    <script src = "http://jcrop-cdn.tapmodo.com/v0.9.12/js/jquery.Jcrop.min.js"></script>
    <link rel = "stylesheet" href = "http://jcrop-cdn.tapmodo.com/v0.9.12/css/jquery.Jcrop.css" type = "text/css" />

    <script type = "text/javascript">
         $(document).delegate(':file', 'change', function() {
            picture(this);
            console.info('running');
        });

         //$(document).delegate(':form', 'change', function() {

        var picture_width;
        var picture_height;
        var crop_max_width = 300;
        var crop_max_height = 300;
        function picture(input) {
            if (input.files && input.files[0]) {
                var reader = new FileReader();
                reader.onload = function (e) {
                    $("#jcrop, #preview").html("").append("<img src=\""+e.target.result+"\" alt=\"\" />");
                    picture_width = $("#preview img").width();
                    picture_height = $("#preview img").height();
                    $("#jcrop  img").Jcrop({
                        onChange: canvas,
                        onSelect: canvas,
                        boxWidth: crop_max_width,
                        boxHeight: crop_max_height
                    });
                }
                reader.readAsDataURL(input.files[0]);
            }
        }
        function canvas(coords){
            var imageObj = $("#jcrop img")[0];
            var canvas = $("#canvas")[0];
            canvas.width  = coords.w;
            canvas.height = coords.h;
            var context = canvas.getContext("2d");
            context.drawImage(imageObj, coords.x, coords.y, coords.w, coords.h, 0, 0, canvas.width, canvas.height);
            png();
        }
        function png() {
            var png = $("#canvas")[0].toDataURL('image/png');
            $("#png").val(png);
        }
        function dataURLtoBlob(dataURL) {
            var BASE64_MARKER = ';base64,';
            if (dataURL.indexOf(BASE64_MARKER) == -1) {
                var parts = dataURL.split(',');
                var contentType = parts[0].split(':')[1];
                var raw = decodeURIComponent(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});
        }
    </script>
    </head>
    <body>
       <form id = "form">
        <h2>Image file select</h2>
        <input id = "file" type = "file" onchange = "imageLoad()" />
        <h2>Uploaded Image</h2>
        <div id = "jcrop"></div>
        <h2>Cropped Image</h2>
        <canvas id = "canvas"></canvas>
        <input id = "png" type = "hidden" />
        <h2>Submit form</h2>
        <input type = "submit" value = "Upload form data and image" />
       </form>
    </body>
</html>

Предоставление кода - это хорошо, но некоторые объяснения того, почему ваш код работает и какие ошибки делал человек, задающий вопрос, помогут людям понять ваш ответ. из обзора

Vaibhav Vishal 17.07.2019 12:42

// Set constraints for the video stream
var constraints = { video: { facingMode: "user" }, audio: false };
// Define constants
const cameraView = document.querySelector("#camera--view"),
    cameraOutput = document.querySelector("#camera--output"),
    cameraSensor = document.querySelector("#camera--sensor"),
    cameraTrigger = document.querySelector("#camera--trigger")
// Access the device camera and stream to cameraView
function cameraStart() {
    navigator.mediaDevices
        .getUserMedia(constraints)
        .then(function(stream) {
        track = stream.getTracks()[0];
        cameraView.srcObject = stream;
    })
    .catch(function(error) {
        console.error("Oops. Something is broken.", error);
    });
}
// Take a picture when cameraTrigger is tapped
cameraTrigger.onclick = function() {
    cameraSensor.width = cameraView.videoWidth;
    cameraSensor.height = cameraView.videoHeight;
    cameraSensor.getContext("2d").drawImage(cameraView, 0, 0);
    cameraOutput.src = cameraSensor.toDataURL("image/webp");
    cameraOutput.classList.add("taken");
};
// Start the video stream when the window loads
window.addEventListener("load", cameraStart, false);
html, body{
  margin: 0;
  padding: 0;
  height: 100%;
  width: 100%;
}
#camera, #camera--view, #camera--sensor, #camera--output{
    position: fixed;
    height: 100%;
    width: 100%;
    object-fit: cover;
}
#camera--view, #camera--sensor, #camera--output{
    transform: scaleX(-1);
    filter: FlipH;
}
#camera--trigger{
    width: 200px;
    background-color: black;
    color: white;
    font-size: 16px;
    border-radius: 30px;
    border: none;
    padding: 15px 20px;
    text-align: center;
    box-shadow: 0 5px 10px 0 rgba(0,0,0,0.2);
    position: fixed;
    bottom: 30px;
    left: calc(50% - 100px);
}
.taken{
    height: 100px!important;
    width: 100px!important;
    transition: all 0.5s ease-in;
    border: solid 3px white;
    box-shadow: 0 5px 10px 0 rgba(0,0,0,0.2);
    top: 20px;
    right: 20px;
    z-index: 2;
}
<html lang=”en”>
<head>
    <meta charset = "utf-8">
    <meta http-equiv = "x-ua-compatible" content = "ie=edge">
    <meta name = "viewport" content = "width=device-width, initial-scale=1">
    <!-- Name of your awesome camera app -->
    <title>Camera App</title>
    <!-- Link to your main style sheet-->
    <link rel = "stylesheet" href = "style.css">
</head>
<body>
    <!-- Camera -->
    <main id = "camera">
        <!-- Camera sensor -->
        <canvas id = "camera--sensor"></canvas>
        <!-- Camera view -->
        <video id = "camera--view" autoplay playsinline></video>
        <!-- Camera output -->
        <img src = "//:0" alt = "" id = "camera--output">
        <!-- Camera trigger -->
        <button id = "camera--trigger">Take a picture</button>
    </main>
    <!-- Reference to your JavaScript file -->
    <script src = "app.js"></script>
</body>
</html>

Пожалуйста, добавьте несколько экспалинаций.

Gufran Hasan 17.07.2019 15:15
Error: Oops. Something is broken.
Neurotransmitter 01.07.2020 13:29

Я немного опоздал на вечеринку по этому поводу, но вчера я сам столкнулся с очень похожей проблемой, но вместо этого использовал NodeJS.

В конце концов, мое решение состояло в том, чтобы разбить изображение на его значения RGBA и проверить каждую строку и столбец изображения, чтобы найти, где само изображение фактически начинается по сравнению с BG.

В моем случае я работаю с изображениями размером около 1500 пикселей * 500 пикселей, при этом мое решение занимает около 150-250 мс на изображение для чтения в файле, разбивает его пиксели, вычисляет позиции обрезки и записывает обрезанный файл обратно в диск.

Так как я не смог найти в Интернете никаких хороших библиотек для решения этой проблемы, я сделал свою собственную и опубликовал ее в NPM на случай, если кто-то еще столкнется с той же проблемой и ему понадобится помощь! :-)

https://www.npmjs.com/package/developyn-autocrop

Другие вопросы по теме