diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..13566b8 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,8 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Editor-based HTTP Client requests +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/.idea/inspectionProfiles/profiles_settings.xml b/.idea/inspectionProfiles/profiles_settings.xml new file mode 100644 index 0000000..105ce2d --- /dev/null +++ b/.idea/inspectionProfiles/profiles_settings.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..dc9ea49 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..69b43c1 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/tcc.iml b/.idea/tcc.iml new file mode 100644 index 0000000..d0876a7 --- /dev/null +++ b/.idea/tcc.iml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..35eb1dd --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/FlaskAPI/.dockerignore b/FlaskAPI/.dockerignore new file mode 100644 index 0000000..3edb0b5 --- /dev/null +++ b/FlaskAPI/.dockerignore @@ -0,0 +1,34 @@ +# Include any files or directories that you don't want to be copied to your +# container here (e.g., local build artifacts, temporary files, etc.). +# +# For more help, visit the .dockerignore file reference guide at +# https://docs.docker.com/engine/reference/builder/#dockerignore-file + +**/.DS_Store +**/__pycache__ +**/.venv +**/.classpath +**/.dockerignore +**/.env +**/.git +**/.gitignore +**/.project +**/.settings +**/.toolstarget +**/.vs +**/.vscode +**/*.*proj.user +**/*.dbmdl +**/*.jfm +**/bin +**/charts +**/docker-compose* +**/compose* +**/Dockerfile* +**/node_modules +**/npm-debug.log +**/obj +**/secrets.dev.yaml +**/values.dev.yaml +LICENSE +README.md diff --git a/FlaskAPI/.idea/.gitignore b/FlaskAPI/.idea/.gitignore new file mode 100644 index 0000000..13566b8 --- /dev/null +++ b/FlaskAPI/.idea/.gitignore @@ -0,0 +1,8 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Editor-based HTTP Client requests +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/FlaskAPI/.idea/FlaskAPI.iml b/FlaskAPI/.idea/FlaskAPI.iml new file mode 100644 index 0000000..15b7777 --- /dev/null +++ b/FlaskAPI/.idea/FlaskAPI.iml @@ -0,0 +1,19 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/FlaskAPI/.idea/inspectionProfiles/profiles_settings.xml b/FlaskAPI/.idea/inspectionProfiles/profiles_settings.xml new file mode 100644 index 0000000..105ce2d --- /dev/null +++ b/FlaskAPI/.idea/inspectionProfiles/profiles_settings.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/FlaskAPI/.idea/misc.xml b/FlaskAPI/.idea/misc.xml new file mode 100644 index 0000000..4bdfec8 --- /dev/null +++ b/FlaskAPI/.idea/misc.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/FlaskAPI/.idea/modules.xml b/FlaskAPI/.idea/modules.xml new file mode 100644 index 0000000..6fa8fc8 --- /dev/null +++ b/FlaskAPI/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/FlaskAPI/.vscode/launch.json b/FlaskAPI/.vscode/launch.json new file mode 100644 index 0000000..6a28b4c --- /dev/null +++ b/FlaskAPI/.vscode/launch.json @@ -0,0 +1,17 @@ +{ + "version": "0.0.1", + "configurations": [ + + { + "name": "Python: Flask", + "type": "python", + "request": "launch", + "module": "flask", + "env": { "FLASK_APP": "app.py", "FLASK_DEBUG": "1" }, + "args": ["run", "--no-debugger", "--no-reload"], + "jinja": true, + "justMyCode": true + } + + ] +} diff --git a/FlaskAPI/.vscode/settings.json b/FlaskAPI/.vscode/settings.json new file mode 100644 index 0000000..e69de29 diff --git a/FlaskAPI/Dockerfile b/FlaskAPI/Dockerfile new file mode 100644 index 0000000..b6a5924 --- /dev/null +++ b/FlaskAPI/Dockerfile @@ -0,0 +1,45 @@ +# syntax=docker/dockerfile:1 + +# Comments are provided throughout this file to help you get started. +# If you need more help, visit the Dockerfile reference guide at +# https://docs.docker.com/engine/reference/builder/ + +ARG PYTHON_VERSION=3.10.12 +FROM python:${PYTHON_VERSION}-slim as base + +# Prevents Python from writing pyc files. +ENV PYTHONDONTWRITEBYTECODE=1 + +# Keeps Python from buffering stdout and stderr to avoid situations where +# the application crashes without emitting any logs due to buffering. +ENV PYTHONUNBUFFERED=1 + +WORKDIR /app + +# Copy the source code into the container. +COPY . . + +RUN apt-get update && apt-get install -y imagemagick && apt-get install -y wget && ls + +RUN wget https://files.ivanch.me/api/public/dl/iFuXSNhw/small-image.png && \ + wget https://files.ivanch.me/api/public/dl/81Bkht5C/big-image.png && \ + wget https://files.ivanch.me/api/public/dl/nAndfAjK/video.mp4 && \ + rm -rf runtimes && \ + mkdir -p ./static && \ + mv small-image.png ./static && \ + mv big-image.png ./static && \ + mv video.mp4 ./static + +# Download dependencies as a separate step to take advantage of Docker's caching. +# Leverage a cache mount to /root/.cache/pip to speed up subsequent builds. +# Leverage a bind mount to requirements.txt to avoid having to copy them into +# into this layer. +RUN --mount=type=cache,target=/root/.cache/pip \ + --mount=type=bind,source=requirements.txt,target=requirements.txt \ + python -m pip install -r requirements.txt + +# Expose the port that the application listens on. +EXPOSE 5000 + +# Run the application. +CMD gunicorn 'app:app' --bind=0.0.0.0:5000 diff --git a/FlaskAPI/__pycache__/app.cpython-310.pyc b/FlaskAPI/__pycache__/app.cpython-310.pyc new file mode 100644 index 0000000..c38168b Binary files /dev/null and b/FlaskAPI/__pycache__/app.cpython-310.pyc differ diff --git a/FlaskAPI/app.py b/FlaskAPI/app.py new file mode 100644 index 0000000..b048e75 --- /dev/null +++ b/FlaskAPI/app.py @@ -0,0 +1,12 @@ +from flask import Flask +from controllers.status import status_blueprint +from controllers.image import image_blueprint + +app = Flask(__name__) + +if __name__ == '__main__': + app.run() + +# +app.register_blueprint(status_blueprint) +app.register_blueprint(image_blueprint) \ No newline at end of file diff --git a/FlaskAPI/blurred_temp_image.jpeg b/FlaskAPI/blurred_temp_image.jpeg new file mode 100644 index 0000000..77ff865 Binary files /dev/null and b/FlaskAPI/blurred_temp_image.jpeg differ diff --git a/FlaskAPI/compose.yaml b/FlaskAPI/compose.yaml new file mode 100644 index 0000000..94e7d9c --- /dev/null +++ b/FlaskAPI/compose.yaml @@ -0,0 +1,49 @@ +# Comments are provided throughout this file to help you get started. +# If you need more help, visit the Docker compose reference guide at +# https://docs.docker.com/compose/compose-file/ + +# Here the instructions define your application as a service called "server". +# This service is built from the Dockerfile in the current directory. +# You can add other services your application may depend on here, such as a +# database or a cache. For examples, see the Awesome Compose repository: +# https://github.com/docker/awesome-compose +services: + server: + build: + context: . + ports: + - 5000:5000 + +# The commented out section below is an example of how to define a PostgreSQL +# database that your application can use. `depends_on` tells Docker Compose to +# start the database before your application. The `db-data` volume persists the +# database data between container restarts. The `db-password` secret is used +# to set the database password. You must create `db/password.txt` and add +# a password of your choosing to it before running `docker compose up`. +# depends_on: +# db: +# condition: service_healthy +# db: +# image: postgres +# restart: always +# user: postgres +# secrets: +# - db-password +# volumes: +# - db-data:/var/lib/postgresql/data +# environment: +# - POSTGRES_DB=example +# - POSTGRES_PASSWORD_FILE=/run/secrets/db-password +# expose: +# - 5432 +# healthcheck: +# test: [ "CMD", "pg_isready" ] +# interval: 10s +# timeout: 5s +# retries: 5 +# volumes: +# db-data: +# secrets: +# db-password: +# file: db/password.txt + diff --git a/FlaskAPI/controllers/__pycache__/image.cpython-310.pyc b/FlaskAPI/controllers/__pycache__/image.cpython-310.pyc new file mode 100644 index 0000000..7cc4314 Binary files /dev/null and b/FlaskAPI/controllers/__pycache__/image.cpython-310.pyc differ diff --git a/FlaskAPI/controllers/__pycache__/status.cpython-310.pyc b/FlaskAPI/controllers/__pycache__/status.cpython-310.pyc new file mode 100644 index 0000000..1eb22a4 Binary files /dev/null and b/FlaskAPI/controllers/__pycache__/status.cpython-310.pyc differ diff --git a/FlaskAPI/controllers/image.py b/FlaskAPI/controllers/image.py new file mode 100644 index 0000000..4083088 --- /dev/null +++ b/FlaskAPI/controllers/image.py @@ -0,0 +1,41 @@ +from services.image import ImageService +from static.image_helper import ImageHelper +from flask import request, Response, Blueprint, jsonify, send_file + +image_blueprint = Blueprint('image_blueprint', __name__) +image_service = ImageService() + + +@image_blueprint.route('/image/blur', methods=['POST']) +def blur_image(): + radius = int(request.form.get('radius')) + image = request.files.get('file') + + if radius and image: + return send_file(image_service.box_blur_image(image, radius), + mimetype='image/jpeg', + as_attachment=True, + download_name='blurred_image.jpeg') + + return "Bad request", 400 + + +@image_blueprint.route('/image/load-small-image', methods=['GET']) +def get_simple_image(): + return send_file(image_service.get_simple_image(), + mimetype='image/png', + as_attachment=True, + download_name='small-image.png') + + +@image_blueprint.route('/image/load-big-image', methods=['GET']) +def get_big_image(): + return send_file(image_service.get_big_image(), + mimetype='image/png', + as_attachment=True, + download_name='big-image.png') + + +@image_blueprint.route('/image/save-big-image', methods=['POST']) +def save_image(): + pass diff --git a/FlaskAPI/controllers/status.py b/FlaskAPI/controllers/status.py new file mode 100644 index 0000000..5d777ad --- /dev/null +++ b/FlaskAPI/controllers/status.py @@ -0,0 +1,19 @@ +from flask import jsonify, Blueprint + +status_blueprint = Blueprint('status_blueprint', __name__) + + +class StatusController: + def __init__(self): + pass + + def return_ok(self): + return jsonify(status=200) + + +status_controller = StatusController() + + +@status_blueprint.route('/status/ok', methods=['GET']) +def return_ok(): + return jsonify(status=200) diff --git a/FlaskAPI/requirements.txt b/FlaskAPI/requirements.txt new file mode 100644 index 0000000..20ce748 --- /dev/null +++ b/FlaskAPI/requirements.txt @@ -0,0 +1,3 @@ +Flask>=1.0 +gunicorn>=19.9.0 +Wand \ No newline at end of file diff --git a/FlaskAPI/services/__pycache__/image.cpython-310.pyc b/FlaskAPI/services/__pycache__/image.cpython-310.pyc new file mode 100644 index 0000000..1ba3a5e Binary files /dev/null and b/FlaskAPI/services/__pycache__/image.cpython-310.pyc differ diff --git a/FlaskAPI/services/image.py b/FlaskAPI/services/image.py new file mode 100644 index 0000000..6dea1da --- /dev/null +++ b/FlaskAPI/services/image.py @@ -0,0 +1,69 @@ +from wand.image import Image + +from static.image_helper import ImageHelper + + +def box_blur_image_separable(image, blurred_image, radius_x, radius_y): + pixels = image.get_pixels() + blurred_pixels = blurred_image.get_pixels() + + for pixel in pixels: + x, y = pixel[0], pixel[1] + + r_total, g_total, b_total = 0, 0, 0 + pixel_count = 0 + for offset_y in range(-radius_y, radius_y + 1): + for offset_x in range(-radius_x, radius_x + 1): + new_x = x + offset_x + new_y = y + offset_y + + if 0 <= new_x < image.width and 0 <= new_y < image.height: + pixel_color = pixels[new_y * image.width + new_x] + r_total += pixel_color.red + g_total += pixel_color.green + b_total += pixel_color.blue + pixel_count += 1 + + blurred_pixel = blurred_pixels[y * image.width + x] + blurred_pixel.red = int(r_total / pixel_count) + blurred_pixel.green = int(g_total / pixel_count) + blurred_pixel.blue = int(b_total / pixel_count) + + return blurred_image + + +def save_image(file_stream): + with open("image.png", "wb") as file: + file.write(file_stream.read()) + file.close() + + +class ImageService: + def __init__(self): + pass + + def box_blur_image(self, img, radius): + temp_path = 'temp_image.png' + img.save(temp_path) + + with Image(filename=temp_path) as img: + img.blur(radius, 2) + blurred_temp_path = 'blurred_temp_image.png' + img.save(filename='blurred_temp_image.png') + return blurred_temp_path + + + def get_simple_image(self): + with ImageHelper.SimpleImage as img: + img = ImageHelper.SimpleImage + simple_image = 'simple_image.png' + img.save(filename='simple_image.png') + return simple_image + + + def get_big_image(self): + with ImageHelper.BigImage as img: + img = ImageHelper.BigImage + big_image = 'big_image.png' + img.save(filename='big_image.png') + return big_image diff --git a/FlaskAPI/static/__pycache__/image_helper.cpython-310.pyc b/FlaskAPI/static/__pycache__/image_helper.cpython-310.pyc new file mode 100644 index 0000000..f8b5084 Binary files /dev/null and b/FlaskAPI/static/__pycache__/image_helper.cpython-310.pyc differ diff --git a/FlaskAPI/static/image_helper.py b/FlaskAPI/static/image_helper.py new file mode 100644 index 0000000..63aba27 --- /dev/null +++ b/FlaskAPI/static/image_helper.py @@ -0,0 +1,17 @@ +from wand.image import Image + + +class ImageHelper: + SimpleImage = None + BigImage = None + + @staticmethod + def load_images(): + ImageHelper.SimpleImage = Image(filename="./static/small-image.png") + #ImageHelper.SimpleImage.save(filename="./static/small-image.png") + + ImageHelper.BigImage = Image(filename="./static/big-image.png") + #ImageHelper.BigImage.save(filename="./static/big-image.png") + pass + +ImageHelper.load_images() \ No newline at end of file diff --git a/FlaskAPI/temp_image.jpeg b/FlaskAPI/temp_image.jpeg new file mode 100644 index 0000000..25783da Binary files /dev/null and b/FlaskAPI/temp_image.jpeg differ