paramecio2fm/paramecio2/libraries/db/extrafields/imagefield.py

292 lines
9.3 KiB
Python

import os
import sys
from pathlib import Path
from paramecio2.libraries.db.corefields import CharField
from paramecio2.libraries.db.extraforms.fileform import FileForm
from paramecio2.libraries.keyutils import create_key
import traceback
from flask import request
from werkzeug.utils import secure_filename
# from bottle import request
try:
from PIL import Image
except:
print("Unexpected error:", sys.exc_info()[0])
raise
from uuid import uuid4
#from paramecio2.libraries.db.extraforms.fileform import FileForm
class ImageField(CharField):
"""Field for upload images in gif, jpg and png formats"""
def __init__(self, name, save_folder='media/upload/images', sizes=None, module=None, size=255, required=False):
"""
Args:
name (str): The name of field
save_folder (str): The folder where the images are saved
sizes (list): In the future will be used for check sizes of files.
size (int): The size of the new field in database. By default 11.
required (bool): Boolean for define if field is required or not
"""
super().__init__(name, size, required)
self.yes_prefix=True
#self.name_form=FileForm
self.thumbnail={'mini_': 150}
self.yes_thumbnail=False
self.default_quality_thumb=95
self.suffix=''
# Is relative to media folder of paramecio
#if module!=None:
self.save_folder=save_folder
self.file_related=True
self.sizes=sizes
self.name_form=FileForm
self.extra_parameters=[self.save_folder]
def change_folder(self, folder):
pass
def check(self, value):
files_uploaded=request.files
field_file=self.name+'_file'
#if not change
if field_file in files_uploaded:
if files_uploaded[field_file].filename=='':
if value=='':
if self.model:
if self.model.updated:
old_reset=self.model.yes_reset_conditions
self.model.yes_reset_conditions=False
with self.model.select([self.name]) as cur:
for arr_image in cur:
if arr_image[self.name]!='':
try:
os.remove(arr_image[self.name])
except:
pass
#if arr_image[self.name]!=save_file and arr_image[self.name]!='':
#value=arr_image[self.name]
self.model.yes_reset_conditions=old_reset
self.txt_error='Field is empty'
self.error=True
return ''
else:
value=os.path.basename(value)
return self.save_folder+'/'+value
else:
value=os.path.basename(value)
return self.save_folder+'/'+value
# Load image file
#file_bytecode=files_uploaded[field_file].file
filename=secure_filename(files_uploaded[field_file].filename)
try:
im=Image.open(files_uploaded[field_file])
except IOError:
self.error=True
self.txt_error='Error, file not have a valid format'
return ""
real_width=im.size[0]
real_height=im.size[1]
if self.sizes:
if 'maximum' in self.sizes:
if self.sizes['maximum'][0]<real_width or self.sizes['maximum'][1]<real_height:
self.error=True
self.txt_error='Wrong size. Maximum size is '+str(self.sizes['maximum'][0])+'x'+str(self.sizes['maximum'][1])
im.close()
return ""
if 'minimum' in self.sizes:
if self.sizes['minimum'][0]>real_width or self.sizes['minimum'][1]>real_height:
self.error=True
self.txt_error='Wrong size. Minimum size is '+str(self.sizes['minimum'][0])+'x'+str(self.sizes['minimum'][1])
im.close()
return ""
if 'resize' in self.sizes:
height_t=0
width_t=0
if real_height<=self.sizes['resize'][1]:
height_t=self.sizes['resize'][1]
if real_width>self.sizes['resize'][0]:
width_t=self.sizes['resize'][0]
if height_t==0:
ratio=(real_width/width_t)
height_t=round(real_height/ratio)
size=(width_t, height_t)
if width_t>0 and height_t>0:
im.thumbnail(size, 3)
format_image=im.format
if format_image!='JPEG' and format_image!='GIF' and format_image!='PNG':
self.error=True
self.txt_error='Format is wrong. Requires JPEG or PNG formats'
im.close()
return ""
# Create thumbnails and move file
realfilename, ext = os.path.splitext(filename)
prefix=''
if self.yes_prefix==True:
#prefix=uuid4().hex+'_'
prefix=create_key(5).replace('/', '-').replace('#', '-')+self.suffix+'_'
filename=prefix+filename
save_file=self.save_folder+'/'+filename
if self.yes_thumbnail:
for name, width_t in self.thumbnail.items():
im_thumb=im.copy()
ratio=(real_width/width_t)
height_t=round(real_height/ratio)
size=(width_t, height_t)
save_file_thumb=self.save_folder+'/'+name+filename
im_thumb.thumbnail(size, Image.ANTIALIAS)
im_thumb.save(save_file_thumb, "JPEG", quality=self.default_quality_thumb)
im_thumb.close()
# Save file
try:
#Check if directory exists
if not os.path.isdir(self.save_folder):
# Try create if not
try:
p=Path(self.save_folder)
p.mkdir(mode=0o755, parents=True)
except:
im.close()
self.error=True
self.txt_error='Error: cannot create the directory where save the image.Check permissions,'
return ""
#files_uploaded[field_file].save(self.save_folder, overwrite=True)
if os.path.isfile(save_file):
os.remove(save_file)
im.save(save_file)
# Delete old files
if self.model!=None:
if self.model.updated:
#old_conditions=self.model.conditions
old_reset=self.model.yes_reset_conditions
self.model.yes_reset_conditions=False
with self.model.select([self.name]) as cur:
for arr_image in cur:
if arr_image[self.name]!=save_file and arr_image[self.name]!='':
if os.path.isfile(arr_image[self.name]):
os.remove(arr_image[self.name])
self.model.yes_reset_conditions=old_reset
#self.model.conditions=old_conditions
im.close()
return save_file
except:
im.close()
self.error=True
self.txt_error='Error: cannot save the image file, Exists directory for save the file? '+traceback.format_exc()
print(traceback.format_exc())
return ""
def show_formatted(self, value):
return os.path.basename(value)