Построение устройства для изменения размера изображения с помощью Flask, React и Vite
Привет!
В этом уроке я покажу вам, как создать простой ресайзер изображений с помощью Flask, React и Vite.
Требования
- Базовые знания Python/React
- Установленный OpenCV
Создание серверной части
Сначала мы создадим серверную часть с помощью Flask, которая будет обрабатывать загрузку изображений, преобразовывать их и затем предоставлять преобразованное изображение в ответе. Для этого мы будем использовать OpenCV и NumPy.
OpenCV используется для декодирования загруженного изображения, изменения его размера и кодирования в формат, который может быть отправлен клиенту.
NumPy используется для преобразования загруженного файла в формат, с которым может работать OpenCV.
Следуя лучшим практикам, мы будем кодировать сервер, используя виртуальную среду Python. Это легко сделать в Python 3 с помощью следующей команды:
python3 -m venv env
В результате будет создан новый каталог под названием env
. Далее для активации виртуального окружения просто выполните следующую команду:
source env/bin/activate
Теперь вы должны находиться в виртуальной среде Python.
Теперь мы можем установить библиотеки, необходимые для серверной части. Просто создайте новый файл с именем requirements.txt
и заполните его следующими данными:
Flask
flask_cors
opencv-python
numpy
Для установки библиотек просто выполните следующую команду:
pip install -r requirements.txt
Это позволит установить библиотеки, необходимые для работы сервера.
Далее нам нужно написать код для обработки загрузки файла, конвертации и отправки ответа обратно на фронтенд. Создайте новый файл под названием main.py
и импортируйте следующие библиотеки:
from flask import Flask, request, send_file
from flask_cors import CORS
import cv2
import numpy as np
После этого нам нужно инициализировать приложение Flask и отключить CORS, это позволит приложению React получить доступ к серверу без каких-либо проблем.
app = Flask(__name__)
CORS(app)
Далее следует маршрут, который будет использоваться для обработки загрузки файлов.
Он выглядит следующим образом:
@app.route('/upload', methods=['POST'])
def upload():
if 'image' not in request.files:
return 'No file uploaded', 400
file = request.files['image']
if not file.content_type.startswith('image/'):
return 'File is not an image', 400
if file.filename == '':
return 'no selected file', 400
if file:
npimg = np.fromfile(file, np.uint8)
img = cv2.imdecode(npimg, cv2.IMREAD_UNCHANGED)
width = int(request.form.get('width', 1024))
height = int(request.form.get('height', 1024))
resized_image = cv2.resize(img, (width, height))
convert_status, buffer = cv2.imencode('.jpg', resized_image)
if not convert_status:
return 'Failed to convert image', 500
temp_file = 'temp_image.jpg'
cv2.imwrite(temp_file, resized_image)
return send_file(temp_file, as_attachment=True)
Вышеописанное проверяет, присутствует ли файл в запросе, проверяет, является ли он действительным файлом изображения, в противном случае клиенту отправляется ответ об ошибке с HTTP-ответом 400.
Если файл существует и является изображением, он будет изменен в размере и преобразован в jpg-изображение, в случае успешного завершения процесса файл возвращается клиенту.
В заключение нам нужна только функция main
:
if __name__ == '__main__':
app.run(debug=True)
Всё, что было сделано выше, - это запуск приложения.
Далее мы создадим приложение React для работы с фронтендом.
Создание клиентской части
Наконец, нам нужен пользовательский интерфейс для загрузки и преобразования изображения. Для фронт-энда будет использоваться React, который будет создан с помощью Vite. Чтобы создать новый проект Vite, просто выполните следующую команду:
yarn create vite
Следуйте подсказкам, чтобы создать новое приложение React, использующее Javascript. Мы также будем использовать Bootstrap для пользовательского интерфейса и axios для обработки запросов. Эти пакеты можно установить с помощью следующих команд:
yarn add axios
yarn add bootstrap
Чтобы применить стили Bootstrap, добавьте следующую строку в файл src/main.jsx
:
import 'bootstrap/dist/css/bootstrap.min.css';
После этого мы создадим новый компонент React для формы загрузки изображения, создадим новую директорию components
в директории src
и создадим новый файл ImageUploadForm.jsx
, после создания заполним его следующим образом:
import { useState } from 'react';
import axios from 'axios';
const ImageUploadForm = () => {
const [height, setHeight] = useState('1024');
const [width, setWidth] = useState('1024');
const [file, setFile] = useState(null);
const [image, setImage] = useState(null);
const handleSubmit = async (e) => {
e.preventDefault();
const formData = new FormData();
formData.append('height', height);
formData.append('width', width);
formData.append('image', file);
try {
const response = await axios.post('http://localhost:5000/upload', formData, {
headers: { 'Content-Type': 'multipart/form-data' },
responseType: 'blob'
});
const objectURL = URL.createObjectURL(response.data);
setImage(objectURL);
} catch (error) {
console.error('error uploading file', error);
}
};
return (
<>
<form onSubmit={handleSubmit} className="container mt-4">
<div className="mb-3">
<label htmlFor="height" className="form-label">Height:</label>
<input type="number" className="form-control" id="height" value={height} onChange={(e) => setHeight(e.target.value)}/>
</div>
<div className="mb-3">
<label htmlFor="width" className="form-label">Width:</label>
<input type="number" className="form-control" id="width" value={width} onChange={(e) => setWidth(e.target.value)} />
</div>
<div className="mb-3">
<label htmlFor="image" className="form-label">Image:</label>
<input type="file" className="form-control" id="image" onChange={(e) => setFile(e.target.files[0])} />
</div>
<button type="submit" className="btn btn-primary">Submit</button>
</form>
{image && <img src={image} />}
</>
);
}
export default ImageUploadForm;
Вышеописанное отображает форму, содержащую три элемента: один для высоты изображения, один для ширины изображения и один для самого файла изображения.
После того как пользователь выбрал изображение и нажал на кнопку отправки, оно отправляется на сервер flask для преобразования. После того как изображение было преобразовано и возвращено обратно в приложение React, преобразованное изображение отображается в нижней части страницы, чтобы пользователь мог его загрузить.
Готово, теперь мы можем запустить и сервер, и приложение!
Запуск приложения
Чтобы запустить сервер Flask, просто выполните следующую команду в виртуальной среде Python:
python main.py
Чтобы запустить приложение React, просто выполните следующую команду:
yarn dev
Вышеуказанная команда должна автоматически открыть ваш браузер и перенаправить вас в приложение React.
Отсюда попробуйте выбрать файл изображения и нажмите на кнопку Submit, теперь изображение должно быть изменено в размере и отображено в нижней части страницы.
Заключение
Здесь я показал, как обрабатывать загрузку изображений с помощью Flask и преобразовывать их с помощью OpenCV. Мы также использовали React и Vite для создания фронтенда и простой формы, позволяющей пользователю выбрать и преобразовать изображение.
Чтобы улучшить это, я бы хотел обрабатывать несколько загруженных изображений и, возможно, даже поддерживать больше типов конвертации, чем просто jpg.
Дополнительную информацию о выборе изображения через файловый браузер, загрузки его через запрос POST
или PATCH
, сохранения в базе данных и возвращения изображение с помощью запроса GET
вы найдете здесь.
Надеюсь, вы узнали что-то новое из этой статьи, так как я получил массу удовольствия от ее создания, и мне нужно было что-то подобное для личного использования.
Спасибо за прочтение!