Image Upload | Flask – Froala
The following sections describe how to handle image uploads on your server using Flask as a server-side language. For information on the upload workflow refer to the image upload documentation.
Setting up the index page.
The full code should look like this:
The full code should look like this:
server.py
handles the server part for flaskInside server.py, the Image class handles the image upload
from
flaskimport
Flask, request, send_from_directory, jsonifyimport
base64import
datetimefrom
os.pathimport
isfile, joinfrom
mimetypesimport
MimeTypesfrom
osimport
listdirfrom
wand.imageimport
Imageimport
wand.imageimport
hashlibimport
jsonimport
timeimport
hmacimport
copyimport
sysimport
osimport
wand.image BASE_DIR = os.path.dirname(os.path.abspath(__file__)) publicDirectory = os.path.join(BASE_DIR,"public"
)if
not
os.path.exists(publicDirectory): os.makedirs(publicDirectory) app = Flask(__name__, static_url_path =""
)def
get_main_html
()
:return
send_from_directory("./"
,"index.html"
)def
get_public
(path)
:return
send_from_directory("public/"
, path)def
get_static
(path)
:return
send_from_directory("./"
, path)def
upload_image
()
:try
: response = Image.upload(FlaskAdapter(request),"/public/"
)except
Exception: response = {"error"
: str(sys.exc_info()[1
])}return
json.dumps(response)def
upload_image_validation
()
:def
validation
(filePath, mimetype)
:with
wand.image.Image(filename = filePath)as
img:if
img.width != img.height:return
False
return
True
options = {"fieldname"
:"myImage"
,"validation"
: validation }try
: response = Image.upload(FlaskAdapter(request),"/public/"
, options)except
Exception: response = {"error"
: str(sys.exc_info()[1
])}return
json.dumps(response)class
Image
(object)
: defaultUploadOptions = {"fieldname"
:"file"
,"validation"
: {"allowedExts"
: ["gif"
,"jpeg"
,"jpg"
,"png"
,"svg"
,"blob"
],"allowedMimeTypes"
: ["image/gif"
,"image/jpeg"
,"image/pjpeg"
,"image/x-png"
,"image/png"
,"image/svg+xml"
] },"resize"
:None
}def
upload
(req, fileRoute, options = None)
:""" Image upload to disk. Parameters: req: framework adapter to http request. See BaseAdapter. fileRoute: string options: dict optional, see defaultUploadOptions attribute Return: dict: {link: "linkPath"} """
if
optionsis
None
: options = Image.defaultUploadOptionselse
: options = Utils.merge_dicts(Image.defaultUploadOptions, options)return
File.upload(req, fileRoute, options)def
delete
(src)
:""" Delete image from disk. Parameters: src: string """
return
File.delete(src)def
list
(folderPath, thumbPath = None)
:""" List images from disk. Parameters: folderPath: string thumbPath: string Return: list: list of images dicts. example: [{url: "url", thumb: "thumb", name: "name"}, ...] """
if
thumbPath ==None
: thumbPath = folderPath response = [] absoluteFolderPath = Utils.getServerPath() + folderPath imageTypes = Image.defaultUploadOptions["validation"
]["allowedMimeTypes"
] fnames = [ffor
fin
listdir(absoluteFolderPath)if
isfile(join(absoluteFolderPath, f))]for
fnamein
fnames: mime = MimeTypes() mimeType = mime.guess_type(absoluteFolderPath + fname)[0
]if
mimeTypein
imageTypes: response.append({"url"
: folderPath + fname,"thumb"
: thumbPath + fname,"name"
: fname })return
responseclass
Utils
(object)
:""" Utils static class. """
def
hmac
(key, string, hex = False)
:""" Calculate hmac. Parameters: key: string string: string hex: boolean optional, return in hex, else return in binary Return: string: hmax in hex or binary """
try
: hmac256 = hmac.new(key.encode()if
isinstance(key, str)else
key, msg = string.encode("utf-8"
)if
isinstance(string, str)else
string, digestmod = hashlib.sha256)except
Exception: hmac256 = hmac.new(key, msg = string, digestmod = hashlib.sha256)return
hmac256.hexdigest()if
hexelse
hmac256.digest()def
merge_dicts
(a, b, path = None)
:""" Deep merge two dicts without modifying them. Source: http://stackoverflow.com/questions/7204805/dictionaries-of-dictionaries-merge/7205107#7205107 Parameters: a: dict b: dict path: list Return: dict: Deep merged dict. """
aClone = copy.deepcopy(a);if
pathis
None
: path = []for
keyin
b:if
keyin
a:if
isinstance(a[key], dict)and
isinstance(b[key], dict): aClone[key] = Utils.merge_dicts(a[key], b[key], path + [str(key)])else
: aClone[key] = b[key]else
: aClone[key] = b[key]return
aClonedef
getExtension
(filename)
:""" Get filename extension. Parameters: filename: string Return: string: The extension without the dot. """
return
os.path.splitext(filename)[1
][1
:]def
getServerPath
()
:""" Get the path where the server has started. Return: string: serverPath """
return
os.path.abspath(os.path.dirname(sys.argv[0
]))def
isFileValid
(filename, mimetype, allowedExts, allowedMimeTypes)
:""" Test if a file is valid based on its extension and mime type. Parameters: filename string mimeType string allowedExts list allowedMimeTypes list Return: boolean """
if
not
allowedExtsor
not
allowedMimeTypes:return
False
extension = Utils.getExtension(filename)return
extension.lower()in
allowedExtsand
mimetypein
allowedMimeTypesdef
isValid
(validation, filePath, mimetype)
:""" Generic file validation. Parameters: validation: dict or function filePath: string mimetype: string """
if
not
validation:return
True
if
callable(validation):return
validation(filePath, mimetype)if
isinstance(validation, dict):return
Utils.isFileValid(filePath, mimetype, validation["allowedExts"
], validation["allowedMimeTypes"
])return
False
class
BaseAdapter
(object)
:""" Interface. Inherit this class to use the lib in your framework. """
def
__init__
(self, request)
:""" Constructor. Parameters: request: http request object from some framework. """
self.request = requestdef
riseError
(self)
:""" Use this when you want to make an abstract method. """
raise
NotImplementedError("Should have implemented this method."
)def
getFilename
(self, fieldname)
:""" Get upload filename based on the fieldname. Parameters: fieldname: string Return: string: filename """
self.riseError()def
getMimetype
(self, fieldname)
:""" Get upload file mime type based on the fieldname. Parameters: fieldname: string Return: string: mimetype """
self.riseError()def
saveFile
(self, fieldname, fullNamePath)
:""" Save the upload file based on the fieldname on the fullNamePath location. Parameters: fieldname: string fullNamePath: string """
self.riseError()class
FlaskAdapter
(BaseAdapter)
:""" Flask Adapter: Check BaseAdapter to see what methods description. """
def
checkFile
(self, fieldname)
:if
fieldnamenot
in
self.request.files:raise
Exception("File does not exist."
)def
getFilename
(self, fieldname)
: self.checkFile(fieldname)return
self.request.files[fieldname].filenamedef
getMimetype
(self, fieldname)
: self.checkFile(fieldname)return
self.request.files[fieldname].content_typedef
saveFile
(self, fieldname, fullNamePath)
: self.checkFile(fieldname) file = self.request.files[fieldname] file.save(fullNamePath)