diff --git a/frappe/core/doctype/file/file.py b/frappe/core/doctype/file/file.py index 473d810a9f..1642e857c5 100755 --- a/frappe/core/doctype/file/file.py +++ b/frappe/core/doctype/file/file.py @@ -30,7 +30,7 @@ import frappe from frappe import _, conf from frappe.model.document import Document from frappe.utils import call_hook_method, cint, cstr, encode, get_files_path, get_hook_method, random_string, strip - +from frappe.utils.image import strip_exif_data class MaxFileSizeReachedError(frappe.ValidationError): pass @@ -456,6 +456,7 @@ class File(Document): def save_file(self, content=None, decode=False, ignore_existing_file_check=False): file_exists = False self.content = content + if decode: if isinstance(content, text_type): self.content = content.encode("utf-8") @@ -466,10 +467,15 @@ class File(Document): if not self.is_private: self.is_private = 0 + + self.content_type = mimetypes.guess_type(self.file_name)[0] + + if self.content_type and "image" in self.content_type: + self.content = strip_exif_data(self.content, self.content_type) + self.file_size = self.check_max_file_size() self.content_hash = get_content_hash(self.content) - self.content_type = mimetypes.guess_type(self.file_name)[0] - + duplicate_file = None # check if a file exists with the same content hash and is also in the same folder (public or private) diff --git a/frappe/utils/image.py b/frappe/utils/image.py index 1eada5acca..3d3d98a28c 100644 --- a/frappe/utils/image.py +++ b/frappe/utils/image.py @@ -5,7 +5,7 @@ from __future__ import unicode_literals, print_function import os def resize_images(path, maxdim=700): - import Image + from PIL import Image size = (maxdim, maxdim) for basepath, folders, files in os.walk(path): for fname in files: @@ -17,3 +17,26 @@ def resize_images(path, maxdim=700): im.save(os.path.join(basepath, fname)) print("resized {0}".format(os.path.join(basepath, fname))) + +def strip_exif_data(content, content_type): + """ Strips exif from image files which support it. + + Works by creating a new Image object which ignores exif by + default and then extracts the binary data back into content. + + Returns: stripped image content + """ + + from PIL import Image + import io + + original_image = Image.open(io.BytesIO(content)) + output = io.BytesIO() + + new_image = Image.new(original_image.mode, original_image.size) + new_image.putdata(list(original_image.getdata())) + new_image.save(output, format=content_type.split('/')[-1].upper()) + + content = output.getvalue() + + return content \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index de9e675a67..92ea0e5572 100644 --- a/requirements.txt +++ b/requirements.txt @@ -73,4 +73,5 @@ pycryptodome==3.9.8 paytmchecksum==1.7.0 wrapt==1.10.11 razorpay==1.2.0 -rsa>=4.1 # not directly required, pinned by Snyk to avoid a vulnerability \ No newline at end of file +rsa>=4.1 # not directly required, pinned by Snyk to avoid a vulnerability +pillow==8.0.1 \ No newline at end of file