forked from expo/troggle
fix many glitches for unusual JPGs
This commit is contained in:
@@ -97,10 +97,19 @@ def chaosmonkey(n):
|
||||
def unique_slug(text, n):
|
||||
"""This gives an almost-unique id based on the text,
|
||||
2 hex digits would seem adequate, but we might get a collision.
|
||||
Not used anywhere.
|
||||
Deterministic
|
||||
"""
|
||||
sha.update(text.encode('utf-8'))
|
||||
return sha.hexdigest()[0:n]
|
||||
|
||||
def random_slug(text, n):
|
||||
"""This gives an almost-unique id based on the text,
|
||||
2 hex digits would seem adequate, but we might get a collision.
|
||||
Random
|
||||
"""
|
||||
text = text + alphabet_suffix(3)
|
||||
sha.update(text.encode('utf-8'))
|
||||
return sha.hexdigest()[0:n]
|
||||
|
||||
def alphabet_suffix(n):
|
||||
"""This is called repeatedly during initial parsing import, hence the cached list
|
||||
@@ -230,10 +239,10 @@ def get_cookie(request):
|
||||
so having a blank is best.
|
||||
"""
|
||||
# NO_COOKIE_DEFAULT = 'Unset Cookie <hohlenforscher@potatohut.expo>'
|
||||
print(f"-- Getting cookie...")
|
||||
# print(f"-- Getting cookie...")
|
||||
editor_id = request.COOKIES.get('editor_id', "") # if no cookie, then default string ""
|
||||
editor = git_string(editor_id) # belt and braces, should have been validity checked on saving already
|
||||
print(f"-- Cookie to be used: {editor=}")
|
||||
# print(f"-- Cookie to be used: {editor=}")
|
||||
return editor
|
||||
|
||||
def git_string(author_string):
|
||||
@@ -248,7 +257,7 @@ def git_string(author_string):
|
||||
return ""
|
||||
|
||||
if author_regex.match(author_string):
|
||||
print(f"++ Is valid git-compatible author string: '{author_string}'")
|
||||
# print(f"++ Is valid git-compatible author string: '{author_string}'")
|
||||
return author_string
|
||||
else:
|
||||
editor = author_string.replace("@","_at_")
|
||||
@@ -267,7 +276,7 @@ def git_add(filename, cwd, commands=[]):
|
||||
|
||||
# what is the purpose of this 'git diff' ? To prevent merge conflicts happening I guess,
|
||||
# so we do not have to reverse a 'git add'
|
||||
print(f"git diff {filename} in {cwd}")
|
||||
# print(f"git diff {filename} in {cwd}")
|
||||
cmd_diff = [git, "diff", filename]
|
||||
commands.append(cmd_diff)
|
||||
cp_diff = subprocess.run(cmd_diff, cwd=cwd, capture_output=True, text=True)
|
||||
@@ -349,11 +358,9 @@ def add_commit(fname, message, editor):
|
||||
|
||||
def write_binary_file(filepath, content):
|
||||
print(f"write_binary_file: {filepath}")
|
||||
write_files([(filepath, content, "")])
|
||||
|
||||
def write_files(files):
|
||||
for filepath, content, encoding in files:
|
||||
filename = filepath.name
|
||||
write_files([(filepath, content, "")]) # null encoding does "wb"
|
||||
|
||||
def ensure_dir_exists(filepath):
|
||||
if filepath.is_dir():
|
||||
raise OSError(
|
||||
f"CANNOT write this file {filepath} as this is an existing DIRECTORY."
|
||||
@@ -369,6 +376,11 @@ def write_files(files):
|
||||
raise OSError(
|
||||
f"CANNOT make the directory for {filepath}. Ask a nerd to fix this: {e}"
|
||||
)
|
||||
|
||||
def write_files(files):
|
||||
for filepath, content, encoding in files:
|
||||
filename = filepath.name
|
||||
ensure_dir_exists(filepath)
|
||||
if encoding:
|
||||
mode = "w"
|
||||
kwargs = {"encoding": encoding}
|
||||
@@ -377,7 +389,7 @@ def write_files(files):
|
||||
kwargs = {}
|
||||
try:
|
||||
with open(filepath, mode, **kwargs) as f:
|
||||
print(f"WRITING {filepath} ")
|
||||
# print(f"WRITING {filepath} ")
|
||||
f.write(content)
|
||||
except PermissionError as e:
|
||||
raise PermissionError(
|
||||
|
||||
@@ -16,7 +16,10 @@ from django.conf import settings as django_settings
|
||||
from PIL import Image
|
||||
|
||||
import troggle.settings as settings
|
||||
from troggle.core.utils import COOKIE_MAX_AGE, WriteAndCommitError, get_cookie, git_string, write_binary_file, write_and_commit, current_expo
|
||||
from troggle.core.utils import ( COOKIE_MAX_AGE,
|
||||
WriteAndCommitError, get_cookie, git_string, write_binary_file,
|
||||
write_and_commit, current_expo, random_slug, ensure_dir_exists
|
||||
)
|
||||
|
||||
from .auth import login_required_if_public
|
||||
|
||||
@@ -120,11 +123,11 @@ def new_image_form(request, path):
|
||||
THUMB_QUALITY = 70
|
||||
IMAGE_QUALITY = 85
|
||||
directory = get_dir(path)
|
||||
print(f"new_image_form(): {directory=} {path=}")
|
||||
# print(f"new_image_form(): {directory=} {path=}")
|
||||
|
||||
editor = get_cookie(request)
|
||||
print(f"{django_settings.FILE_UPLOAD_MAX_MEMORY_SIZE=}")
|
||||
FILE_UPLOAD_MAX_MEMORY_SIZE = 0 # force uploaded files to be temporary in /tmp, not in-memory
|
||||
# print(f"{django_settings.FILE_UPLOAD_MAX_MEMORY_SIZE=}")
|
||||
# FILE_UPLOAD_MAX_MEMORY_SIZE = 0 # force uploaded files to be temporary in /tmp, not in-memory
|
||||
if request.method == "POST":
|
||||
# print(f"new_image_form(): POST ")
|
||||
form = NewWebImageForm(request.POST, request.FILES, directory=directory)
|
||||
@@ -156,11 +159,11 @@ def new_image_form(request, path):
|
||||
# int(f"new_image_form() After DUMP {exif=}")
|
||||
except:
|
||||
exif = None
|
||||
if not descrip:
|
||||
# date and time from exif data
|
||||
descrip = f"{exif_dict['Exif'][36867].decode()} {exif_dict['Exif'][36880].decode()}"
|
||||
if not year:
|
||||
year = exif_dict['Exif'][36867].decode()[:4]
|
||||
# date and time from exif data
|
||||
if 36867 in exif_dict['Exif'] and 36880 in exif_dict['Exif']:
|
||||
descrip += f"\n\n{exif_dict['Exif'][36867].decode()} {exif_dict['Exif'][36880].decode()}"
|
||||
if not year:
|
||||
year = exif_dict['Exif'][36867].decode()[:4]
|
||||
else:
|
||||
year = current_expo() # replace with year from photo exif if possible
|
||||
exif = None
|
||||
@@ -169,13 +172,13 @@ def new_image_form(request, path):
|
||||
# print(f"new_image_form(): {i.size=}")
|
||||
if width > MAX_IMAGE_WIDTH or height > MAX_IMAGE_HEIGHT:
|
||||
scale = max(width / MAX_IMAGE_WIDTH, height / MAX_IMAGE_HEIGHT)
|
||||
print(f"new_image_form(): rescaling {scale=}")
|
||||
# print(f"new_image_form(): rescaling {scale=}")
|
||||
try:
|
||||
i = i.resize((int(width / scale), int(height / scale)), Image.LANCZOS)
|
||||
except Exception as e:
|
||||
print(f"new_image_form(): rescaling exception: {e} ")
|
||||
|
||||
print(f"new_image_form(): rescaled ")
|
||||
# print(f"new_image_form(): rescaled ")
|
||||
tscale = max(width / THUMBNAIL_WIDTH, height / THUMBNAIL_HEIGHT)
|
||||
t = i.resize((int(width / tscale), int(height / tscale)), Image.LANCZOS)
|
||||
t = t.convert('RGB')
|
||||
@@ -197,7 +200,7 @@ def new_image_form(request, path):
|
||||
t.save(tb, format='JPEG', quality = THUMB_QUALITY)
|
||||
|
||||
image_rel_path, thumb_rel_path, desc_rel_path = form.get_rel_paths()
|
||||
print(f"new_image_form(): \n {image_rel_path=}\n {thumb_rel_path=}\n {desc_rel_path=}")
|
||||
# print(f"new_image_form(): \n {image_rel_path=}\n {thumb_rel_path=}\n {desc_rel_path=}")
|
||||
image_page_template = loader.get_template("image_page_template.html")
|
||||
image_page = image_page_template.render(
|
||||
{
|
||||
@@ -211,7 +214,7 @@ def new_image_form(request, path):
|
||||
image_path, thumb_path, desc_path = form.get_full_paths()
|
||||
# Create directories if required
|
||||
for full_path in image_path, thumb_path, desc_path:
|
||||
print(full_path, full_path.parent)
|
||||
# print(full_path, full_path.parent)
|
||||
full_path.parent.mkdir(parents=True, exist_ok=True)
|
||||
try:
|
||||
change_message = form.cleaned_data["change_message"]
|
||||
@@ -264,7 +267,7 @@ def save_original_in_expofiles(f, year, photographer):
|
||||
will catch photos uploaded directly from phones which otherwise never
|
||||
get recorded properly in original format.
|
||||
|
||||
Django does small files in memory, which is a pain.
|
||||
Django does small files <2.5 MB in memory, which is a pain.
|
||||
"""
|
||||
if photographer:
|
||||
photographer = photographer.strip().replace(" ","")
|
||||
@@ -272,15 +275,29 @@ def save_original_in_expofiles(f, year, photographer):
|
||||
photographer = "Anonymous"
|
||||
directory = settings.EXPOFILES / "photos" / year / photographer / "expoweb_originals"
|
||||
filepath = (directory / f.name)
|
||||
ensure_dir_exists(filepath)
|
||||
|
||||
if isinstance(f, InMemoryUploadedFile):
|
||||
print("In-memory file content:", f,f.content_type, f.size, f.charset, f.content_type_extra, f.read())
|
||||
# print("In-memory file content:", f,f.content_type, f.size, f.charset, f.content_type_extra, f.read())
|
||||
f.open() # rewind to beginning
|
||||
content = f.read()
|
||||
print(f"In-memory file content: content read: {len(content)}")
|
||||
# THIS DOES NOT WORK, which is why we force all uploads to use a temporary file not in-memory
|
||||
write_binary_file(filepath, content)
|
||||
elif isinstance(f, TemporaryUploadedFile):
|
||||
dest = shutil.move(f.temporary_file_path(), filepath)
|
||||
if filepath.is_file:
|
||||
print(f"+++++ Out of cheese error\n Destination EXISTS {filepath}")
|
||||
tail = random_slug(str(filepath), 2)
|
||||
newname = f"{filepath.stem}_{tail}{filepath.suffix}"
|
||||
filepath = filepath.parent / newname
|
||||
print(f"+++++ The turtle moves\n Attempting to use {filepath}")
|
||||
if Path(f.temporary_file_path()).is_file:
|
||||
# print(f"+++++ Found {f.temporary_file_path()}")
|
||||
try:
|
||||
dest = shutil.move(f.temporary_file_path(), filepath)
|
||||
except Exception as e:
|
||||
print("+++++ ",e)
|
||||
raise
|
||||
else:
|
||||
print(f"+++++ Out of cheese error\n Can't find {f.temporary_file_path()}")
|
||||
else:
|
||||
msg = f"Unknown uploaded file type: {f}, should be a temporary file or in-memory."
|
||||
print(msg)
|
||||
|
||||
Reference in New Issue
Block a user