backend/api/views.py
2022-06-15 12:05:29 +02:00

278 lines
8.3 KiB
Python
Executable File

from rest_framework import generics, views, status
from rest_framework.response import Response
from django.shortcuts import get_list_or_404
from photo_log.models import PhotoGroup, Photo, PhotoLog, PhotoTag
from .serializers import (
PhotoGroupSerializer,
PhotosSerializer,
PhotoSerializer,
PhotoUpdateSerializer,
PhotoLogSerializer,
PhotoLogsSerializer,
PhotoTagSerializer,
)
from .photolog_generator import generate_photolog_from_latex
from .autocrop.autocrop import autocrop
from django.db.models import FileField
from django.core.files.uploadedfile import InMemoryUploadedFile
from django.core.files.base import ContentFile
from io import BytesIO
from PIL import Image, ExifTags
class PhotoTagsAPIView(generics.ListAPIView):
queryset = PhotoTag.objects.all()
serializer_class = PhotoTagSerializer
class CreatePhotoTagAPIView(generics.CreateAPIView):
queryset = PhotoTag.objects.all()
serializer_class = PhotoTagSerializer
class RetrieveUpdateDestroyPhotoTagAPIView(generics.RetrieveUpdateDestroyAPIView):
queryset = PhotoTag.objects.all()
serializer_class = PhotoTagSerializer
class PhotoGroupAPIView(generics.ListAPIView):
queryset = PhotoGroup.objects.all()
serializer_class = PhotoGroupSerializer
class PhotosAPIView(generics.ListAPIView):
serializer_class = PhotoSerializer
def get_queryset(self):
queryset = Photo.objects.all()
self.serializer_class = PhotosSerializer
photogroup = self.request.query_params.get('photogroup')
if photogroup is not None:
queryset = get_list_or_404(queryset, group=photogroup)
self.serializer_class = PhotoSerializer
return queryset
class PhotoAPIView(generics.RetrieveAPIView):
serializer_class = PhotoSerializer
queryset = Photo.objects.all()
class AddPhotoAPIView(generics.CreateAPIView):
queryset = Photo.objects.all()
serializer_class = PhotoSerializer
class AddPhotoGroupAPIView(generics.CreateAPIView):
queryset = PhotoGroup.objects.all()
serializer_class = PhotoGroupSerializer
class PhotoLogAPIView(generics.RetrieveAPIView):
serializer_class = PhotoLogSerializer
queryset = PhotoLog.objects.all()
class PhotoLogsAPIView(generics.ListAPIView):
serializer_class = PhotoLogsSerializer
queryset = PhotoLog.objects.all()
class AddPhotoLogAPIView(generics.CreateAPIView):
queryset = PhotoLog.objects.all()
serializer_class = PhotoLogSerializer
class DestroyPhotoLogAPIView(generics.DestroyAPIView):
queryset = PhotoLog.objects.all()
serializer_class = PhotoLogSerializer
class DestroyPhotoAPIView(generics.DestroyAPIView):
queryset = Photo.objects.all()
serializer_class = PhotoSerializer
class UpdatePhotoLogAPIView(generics.UpdateAPIView):
queryset = PhotoLog.objects.all()
serializer_class = PhotoLogSerializer
lookup_field = 'pk'
def update(self, request, *args, **kwargs):
instance = self.get_object()
serializer = self.get_serializer(instance, data=request.data, partial=True)
if serializer.is_valid():
serializer.save()
return Response({'ok'})
else:
return Response({"error": serializer.errors}, status=status.HTTP_400_BAD_REQUEST)
class UpdatePhotoAPIView(generics.UpdateAPIView):
queryset = Photo.objects.all()
serializer_class = PhotoUpdateSerializer
lookup_field = 'pk'
def update(self, request, *args, **kwargs):
instance = self.get_object()
serializer = self.get_serializer(instance, data=request.data, partial=True)
if serializer.is_valid():
serializer.save()
return Response({'ok'})
else:
return Response({"error": serializer.errors}, status=status.HTTP_400_BAD_REQUEST)
class GeneratePhotoLogAPIView(generics.RetrieveAPIView):
queryset = PhotoLog.objects.all()
serializer_class = PhotoLogSerializer
def get(self, request, *args, **kwargs):
photolog = self.get_object()
photolog_data = self.get_serializer(photolog).data
if photolog_data:
title = photolog_data['title']
date = photolog_data['date']
render_date = photolog_data['render_date']
start_slide_image = photolog_data['start_slide_image']
slides = photolog_data['slides']
log_bytes = generate_photolog_from_latex(request, title, date, render_date, start_slide_image, slides)
if log_bytes:
photolog.pdf.save('log.pdf', ContentFile(log_bytes))
return Response({'pdf': 'https://zierle-training.riezel.com%s' % str(photolog.pdf.url)})
return Response({"error": "Not Found"}, status=status.HTTP_404_NOT_FOUND)
def crop_photo_and_save(id, save=False):
return "code run with id " + str(id)
def save_cropped_pillow_image(photo, pil_img):
cropped_img_field = photo.cropped_image
buffer = BytesIO()
pil_img.save(fp=buffer, format="PNG")
pil_img = ContentFile(buffer.getvalue())
img_name = "cropped_image.png"
cropped_img_field.save(img_name, InMemoryUploadedFile(
pil_img,
None, # field_name
img_name, # image name
'image/png',
pil_img.tell, # image size
None
))
def simple_crop_to_bbox(photo):
img = Image.open(photo.original_image)
img = rotateByExif(img)
bbox = photo.bbox_coords
rotate_angle = photo.rotate
if not img:
return None
#if rotate_angle:
# img = img.rotate(rotate_angle, expand=1)
if bbox:
img = img.crop((
bbox[0][0],
bbox[0][1],
bbox[2][0],
bbox[2][1]
))
return img
def rotateByExif(img):
try:
for orientation in ExifTags.TAGS.keys():
if ExifTags.TAGS[orientation]=='Orientation':
break
exif = img._getexif()
if not exif:
return img
if exif[orientation] == 3:
img=img.rotate(180, expand=True)
elif exif[orientation] == 6:
img=img.rotate(270, expand=True)
elif exif[orientation] == 8:
img=img.rotate(90, expand=True)
except (AttributeError, KeyError, IndexError):
# cases: image don't have getexif
pass
return img
class AutoCropPhotoAPIView(generics.RetrieveAPIView):
queryset = Photo.objects.all()
serializer_class = PhotoSerializer
def get(self, request, *args, **kwargs):
photo = None
photo_data = self.get_serializer(self.get_object()).data
if photo_data:
photo_id = photo_data['id']
if photo_id:
if not 'mode' in request.query_params:
return Response({'error':'cropping mode not specified (auto, bbox or inters)'}, status=status.HTTP_400_BAD_REQUEST)
mode = request.query_params.get('mode')
if mode == 'bbox':
photo = Photo.objects.get(id=photo_id)
cropped_img = simple_crop_to_bbox(photo)
save_cropped_pillow_image(photo, cropped_img)
elif mode == 'auto' or mode == 'inters':
photo = Photo.objects.get(id=photo_id)
img = Image.open(photo.original_image)
img = rotateByExif(img)
try:
cropped_img, _, bbox, intersections = autocrop(img)
except Exception:
cropped_img = img
bbox = None
intersections = None
if mode == 'auto':
save_cropped_pillow_image(photo, cropped_img)
if bbox:
photo.bbox_coords = bbox
photo.save()
if intersections:
photo.intersections = intersections
photo.save()
else:
return Response({'error':'invalid cropping mode (auto, bbox or inters)'}, status=status.HTTP_400_BAD_REQUEST)
if photo:
return self.retrieve(request, *args, **kwargs)
return Response({"error": "Not Found"}, status=status.HTTP_404_NOT_FOUND)