diff --git a/MisplaceAI/process_misplaced_manager/urls.py b/MisplaceAI/process_misplaced_manager/urls.py index 7c43f0498adba3e8f0ccd791d19d4f6e3e71bf4d..e5fbda822f847faae7b1f5162b49f6c16cac6619 100644 --- a/MisplaceAI/process_misplaced_manager/urls.py +++ b/MisplaceAI/process_misplaced_manager/urls.py @@ -4,7 +4,7 @@ from rest_framework.routers import DefaultRouter from .views import ( UploadedImageViewSet, UploadedVideoViewSet, normal_detection, - display_results, display_video_results,upload_video + display_results, display_video_results,upload_video, download_image ) router = DefaultRouter() @@ -20,4 +20,7 @@ urlpatterns = [ path('upload-video/', upload_video, name='upload_video'), path('video-results/<int:video_id>/', display_video_results, name='display_video_results'), path('display-results/<int:image_id>/', display_results, name='display_results'), + path('download/<path:file_path>/', download_image, name='download_image'), + + ] diff --git a/MisplaceAI/process_misplaced_manager/views.py b/MisplaceAI/process_misplaced_manager/views.py index aaf6954dd6a211af6232c708d5ae8c8a2b0617b3..6ed5b0b866c3892171be57b7a6f7536cf02bf97b 100644 --- a/MisplaceAI/process_misplaced_manager/views.py +++ b/MisplaceAI/process_misplaced_manager/views.py @@ -17,7 +17,7 @@ from PIL import Image, ExifTags import logging import cv2 from django.conf import settings -from django.http import JsonResponse +from django.http import JsonResponse, HttpResponse, Http404 import numpy as np from moviepy.editor import VideoFileClip, ImageSequenceClip @@ -245,21 +245,16 @@ def process_video_for_misplaced_objects(video_path, frame_interval): - - - - - - - - - - - - - - - - - - \ No newline at end of file +################################################################################################# +####################################### Download Results ######################################## +@api_view(['GET']) +@permission_classes([IsAuthenticated]) +def download_image(request, file_path): + file_path = os.path.join(settings.MEDIA_ROOT, file_path) + if os.path.exists(file_path): + with open(file_path, 'rb') as f: + response = HttpResponse(f.read(), content_type="application/force-download") + response['Content-Disposition'] = f'attachment; filename="{os.path.basename(file_path)}"' + return response + else: + raise Http404 \ No newline at end of file diff --git a/frontend/src/pages/NormalDetection/NormalDetectionPage.js b/frontend/src/pages/NormalDetection/NormalDetectionPage.js index bf9472cc9946e8bfe7978bdc5079771a0a221a34..d4e0b0d66c10d9ad97ad09e97ebc05553f138d2e 100644 --- a/frontend/src/pages/NormalDetection/NormalDetectionPage.js +++ b/frontend/src/pages/NormalDetection/NormalDetectionPage.js @@ -1,7 +1,7 @@ // src/pages/NormalDetection/NormalDetectionPage.js import React, { useState } from 'react'; import { Modal, Button } from 'react-bootstrap'; -import { normalDetection } from '../../services/processMisplacedManagerApi'; +import { normalDetection, downloadImage } from '../../services/processMisplacedManagerApi'; import '../../styles/main.css'; import LoadingIndicator from '../../components/detection/LoadingIndicator'; import DetectionResults from '../../components/detection/DetectionResults'; @@ -65,6 +65,22 @@ const NormalDetectionPage = () => { setDetectionComplete(false); }; + const handleDownload = async () => { + try { + const filePath = resultImageUrl.split('/').pop(); // Get the file name only + const response = await downloadImage(filePath); + const url = window.URL.createObjectURL(new Blob([response.data])); + const link = document.createElement('a'); + link.href = url; + link.setAttribute('download', `detection_result${resultImageUrl.substring(resultImageUrl.lastIndexOf('.'))}`); + document.body.appendChild(link); + link.click(); + document.body.removeChild(link); + } catch (error) { + console.error('Error downloading image:', error); + } + }; + return ( <DetectionContainer title="Upload Image for Normal Detection"> <LoadingIndicator isLoading={isLoading} message="Your photo is being processed, please wait..." /> @@ -81,6 +97,9 @@ const NormalDetectionPage = () => { <> <DetectionResults result={{ output_image_url: resultImageUrl, misplaced_objects: misplacedObjects }} /> <div className="text-center mt-4"> + <Button onClick={handleDownload} className="btn btn-success mr-2"> + Download Image + </Button> <Button onClick={handleReset} className="btn btn-primary"> Detect Another Image </Button> diff --git a/frontend/src/services/processMisplacedManagerApi.js b/frontend/src/services/processMisplacedManagerApi.js index 706674c467397fd735043a10dfe1b35b4a82d9d8..0cc683efa49ff7d51cd239a7742f27830ed05421 100644 --- a/frontend/src/services/processMisplacedManagerApi.js +++ b/frontend/src/services/processMisplacedManagerApi.js @@ -119,4 +119,18 @@ export const getVideoResults = async (id) => { console.error(`Error fetching video results with ID ${id}:`, error); throw error; } +}; + + +// Function to download an image +export const downloadImage = async (filePath) => { + try { + const response = await api.get(`/api/process_misplaced_manager/download/${filePath}/`, { + responseType: 'blob', // Important for handling file downloads + }); + return response; + } catch (error) { + console.error('Error downloading image:', error); + throw error; + } }; \ No newline at end of file