旋转自拍图像在开发中工作但在生产中保存到 S3 存储桶时不起作用?
Rotate selfie image working in development but not working when saving to S3 bucket in production?
我正在尝试修复我在生产中遇到但在开发中没有遇到的图像旋转错误。坚持了几天,非常感谢任何对如何解决这个问题有任何见解的人的帮助!
==上下文==
我正在编写一个具有个人资料图片上传功能的 Django 网络应用程序。为了解决自拍 EXIF 问题(方向不正确),我添加了一个使用 post-save 接收器旋转图像的功能。它在开发中效果很好(当图像在本地保存和存储时),但现在我已经转移到生产环境(Heroku 服务器;将图像保存在 S3 存储桶中),该函数抛出一个 FileNotFound 错误——[Errno 2] 没有这样的文件或目录:'https://db-devsite1.s3.amazonaws.com/media/uploadImage/81c01af5-030f-42ed-b413-91eb8941675b.JPG',即使它是图像的正确文件路径。其他一切仍然很好用。
==查看==
def rotateimage (request):
if request.method == 'POST':
form = uploadImageForm(request.POST, request.FILES)
if form.is_valid():
form.save()
return redirect('rotateimage')
else:
form = uploadImageForm()
==型号==
import os
from django.db import models
from catalog.utilities import rotate_image
from django.urls import reverse
from io import BytesIO
from django.core.files import File
from PIL import Image, ExifTags
from django.db.models.signals import post_save
from django.dispatch import receiver
from django.conf import settings
class uploadImage(models.Model):
uploadImage = models.ImageField(upload_to='uploadImage', blank=True, null=True)
thumbnail = models.ImageField(upload_to='rotateImage', blank=True, null=True)
@receiver(post_save, sender=uploadImage, dispatch_uid="update_image_profile")
def update_image(sender, instance, **kwargs):
if instance.uploadImage:
fullpath = settings.MEDIA_ROOT + instance.uploadImage.url
rotate_image(fullpath)
==实用程序==
from PIL import Image, ExifTags
def rotate_image(filepath):
dev_test = "Off"
if dev_test == "Off":
try:
image = Image.open(filepath)
for orientation in ExifTags.TAGS.keys():
if ExifTags.TAGS[orientation] == 'Orientation':
break
exif = dict(image._getexif().items())
if exif[orientation] == 3:
image = image.rotate(180, expand=True)
elif exif[orientation] == 6:
image = image.rotate(270, expand=True)
elif exif[orientation] == 8:
image = image.rotate(90, expand=True)
image.save(filepath)
image.close()
except (AttributeError, KeyError, IndexError):
# cases: image don't have getexif
pass
else:
try:
image = Image.open(filepath)
image = image.rotate(180, expand=True)
image.save(filepath)
image.close()
except (AttributeError, KeyError, IndexError):
# cases: image don't have getexif
pass
==设置==
import os
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
AWS_LOCATION = 'static'
AWS_ACCESS_KEY_ID = CONFIG['AWS_ACCESS_KEY_ID']
AWS_SECRET_ACCESS_KEY = CONFIG['AWS_SECRET_ACCESS_KEY']
AWS_STORAGE_BUCKET_NAME = CONFIG['AWS_STORAGE_BUCKET_NAME']
AWS_S3_CUSTOM_DOMAIN='%s.s3.amazonaws.com' % AWS_STORAGE_BUCKET_NAME
AWS_S3_OBJECT_PARAMETERS = {
'CacheControl': 'max-age=86400',
}
DEFAULT_FILE_STORAGE = 'dbDevSite.storage_backends.MediaStorage'
STATICFILES_STORAGE = "storages.backends.s3boto3.S3Boto3Storage"
STATICFILES_DIRS = [
os.path.join(BASE_DIR, 'catalog/static'),
]
STATIC_URL='https://%s/%s/' % (AWS_S3_CUSTOM_DOMAIN, AWS_LOCATION)
ADMIN_MEDIA_PREFIX = STATIC_URL + 'admin/'
STATICFILES_FINDERS = ('django.contrib.staticfiles.finders.FileSystemFinder', 'django.contrib.staticfiles.finders.AppDirectoriesFinder',)
AWS_DEFAULT_ACL = None
AWS_PRELOAD_METADATA=True
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'catalog/static/media')
# Heroku: Update database configuration from $DATABASE_URL.
import dj_database_url
db_from_env = dj_database_url.config(conn_max_age=500)
DATABASES['default'].update(db_from_env)
***编辑 - 更新后出现完整错误
Environment:
Request Method: POST
Request URL: https://db-devsite.herokuapp.com/catalog/rotateimage
Django Version: 3.0.1
Python Version: 3.8.0
Installed Applications:
['django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'catalog.apps.CatalogConfig',
'storages']
Installed Middleware:
['django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware']
Traceback (most recent call last):
File "/app/.heroku/python/lib/python3.8/site-packages/django/core/handlers/exception.py", line 34, in inner
response = get_response(request)
File "/app/.heroku/python/lib/python3.8/site-packages/django/core/handlers/base.py", line 115, in _get_response
response = self.process_exception_by_middleware(e, request)
File "/app/.heroku/python/lib/python3.8/site-packages/django/core/handlers/base.py", line 113, in _get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "/app/catalog/views.py", line 18, in rotateimage
form.save()
File "/app/.heroku/python/lib/python3.8/site-packages/django/forms/models.py", line 459, in save
self.instance.save()
File "/app/.heroku/python/lib/python3.8/site-packages/django/db/models/base.py", line 745, in save
self.save_base(using=using, force_insert=force_insert,
File "/app/.heroku/python/lib/python3.8/site-packages/django/db/models/base.py", line 793, in save_base
post_save.send(
File "/app/.heroku/python/lib/python3.8/site-packages/django/dispatch/dispatcher.py", line 173, in send
return [
File "/app/.heroku/python/lib/python3.8/site-packages/django/dispatch/dispatcher.py", line 174, in <listcomp>
(receiver, receiver(signal=self, sender=sender, **named))
File "/app/catalog/models.py", line 31, in update_image
rotate_image(fullpath)
File "/app/catalog/utilities.py", line 9, in rotate_image
image = Image.open(filepath)
File "/app/.heroku/python/lib/python3.8/site-packages/PIL/Image.py", line 2766, in open
fp = builtins.open(filename, "rb")
Exception Type: FileNotFoundError at /catalog/rotateimage
Exception Value: [Errno 2] No such file or directory: 'https://db-devsite1.s3.amazonaws.com/media/uploadImage/81c01af5-030f-42ed-b413-91eb8941675b_Kupxl37.JPG'
编辑这里是 post-保存功能有效的代码解决方案
@receiver(post_save, sender=uploadImage, dispatch_uid="update_image_profile")
def update_image(sender, instance, **kwargs):
if instance.uploadImage:
# Download instance.uploadImage from S3 to temp folder
s3_client = boto3.client('s3')
bucket_name = settings.AWS_STORAGE_BUCKET_NAME
subfolder_name = 'media/'
target_image = str(instance.uploadImage)
image_path = subfolder_name + target_image
image_name = '/tmp/image.jpg'
s3_client.download_file(bucket_name, image_path, image_name)
# Rotate image in temp folder
rotate_image(image_name)
# Upload rotated image from temp folder back to S3
s3_client.upload_file(image_name, bucket_name, image_path)
如果您的代码成功处理了旋转,那么唯一缺少的步骤是 download/upload 图像。
下载:
import boto3
s3_client = boto3.client('s3')
s3_client.download_file('mybucket', 'user1.jpg', '/tmp/image.jpg')
然后,使用您现有的代码旋转图像,最后将其上传到您想要的目的地:
s3_client.upload_file('/tmp/image.jpg', 'mybucket', 'user1.jpg')
我正在尝试修复我在生产中遇到但在开发中没有遇到的图像旋转错误。坚持了几天,非常感谢任何对如何解决这个问题有任何见解的人的帮助!
==上下文==
我正在编写一个具有个人资料图片上传功能的 Django 网络应用程序。为了解决自拍 EXIF 问题(方向不正确),我添加了一个使用 post-save 接收器旋转图像的功能。它在开发中效果很好(当图像在本地保存和存储时),但现在我已经转移到生产环境(Heroku 服务器;将图像保存在 S3 存储桶中),该函数抛出一个 FileNotFound 错误——[Errno 2] 没有这样的文件或目录:'https://db-devsite1.s3.amazonaws.com/media/uploadImage/81c01af5-030f-42ed-b413-91eb8941675b.JPG',即使它是图像的正确文件路径。其他一切仍然很好用。
==查看==
def rotateimage (request):
if request.method == 'POST':
form = uploadImageForm(request.POST, request.FILES)
if form.is_valid():
form.save()
return redirect('rotateimage')
else:
form = uploadImageForm()
==型号==
import os
from django.db import models
from catalog.utilities import rotate_image
from django.urls import reverse
from io import BytesIO
from django.core.files import File
from PIL import Image, ExifTags
from django.db.models.signals import post_save
from django.dispatch import receiver
from django.conf import settings
class uploadImage(models.Model):
uploadImage = models.ImageField(upload_to='uploadImage', blank=True, null=True)
thumbnail = models.ImageField(upload_to='rotateImage', blank=True, null=True)
@receiver(post_save, sender=uploadImage, dispatch_uid="update_image_profile")
def update_image(sender, instance, **kwargs):
if instance.uploadImage:
fullpath = settings.MEDIA_ROOT + instance.uploadImage.url
rotate_image(fullpath)
==实用程序==
from PIL import Image, ExifTags
def rotate_image(filepath):
dev_test = "Off"
if dev_test == "Off":
try:
image = Image.open(filepath)
for orientation in ExifTags.TAGS.keys():
if ExifTags.TAGS[orientation] == 'Orientation':
break
exif = dict(image._getexif().items())
if exif[orientation] == 3:
image = image.rotate(180, expand=True)
elif exif[orientation] == 6:
image = image.rotate(270, expand=True)
elif exif[orientation] == 8:
image = image.rotate(90, expand=True)
image.save(filepath)
image.close()
except (AttributeError, KeyError, IndexError):
# cases: image don't have getexif
pass
else:
try:
image = Image.open(filepath)
image = image.rotate(180, expand=True)
image.save(filepath)
image.close()
except (AttributeError, KeyError, IndexError):
# cases: image don't have getexif
pass
==设置==
import os
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
AWS_LOCATION = 'static'
AWS_ACCESS_KEY_ID = CONFIG['AWS_ACCESS_KEY_ID']
AWS_SECRET_ACCESS_KEY = CONFIG['AWS_SECRET_ACCESS_KEY']
AWS_STORAGE_BUCKET_NAME = CONFIG['AWS_STORAGE_BUCKET_NAME']
AWS_S3_CUSTOM_DOMAIN='%s.s3.amazonaws.com' % AWS_STORAGE_BUCKET_NAME
AWS_S3_OBJECT_PARAMETERS = {
'CacheControl': 'max-age=86400',
}
DEFAULT_FILE_STORAGE = 'dbDevSite.storage_backends.MediaStorage'
STATICFILES_STORAGE = "storages.backends.s3boto3.S3Boto3Storage"
STATICFILES_DIRS = [
os.path.join(BASE_DIR, 'catalog/static'),
]
STATIC_URL='https://%s/%s/' % (AWS_S3_CUSTOM_DOMAIN, AWS_LOCATION)
ADMIN_MEDIA_PREFIX = STATIC_URL + 'admin/'
STATICFILES_FINDERS = ('django.contrib.staticfiles.finders.FileSystemFinder', 'django.contrib.staticfiles.finders.AppDirectoriesFinder',)
AWS_DEFAULT_ACL = None
AWS_PRELOAD_METADATA=True
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'catalog/static/media')
# Heroku: Update database configuration from $DATABASE_URL.
import dj_database_url
db_from_env = dj_database_url.config(conn_max_age=500)
DATABASES['default'].update(db_from_env)
***编辑 - 更新后出现完整错误
Environment:
Request Method: POST
Request URL: https://db-devsite.herokuapp.com/catalog/rotateimage
Django Version: 3.0.1
Python Version: 3.8.0
Installed Applications:
['django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'catalog.apps.CatalogConfig',
'storages']
Installed Middleware:
['django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware']
Traceback (most recent call last):
File "/app/.heroku/python/lib/python3.8/site-packages/django/core/handlers/exception.py", line 34, in inner
response = get_response(request)
File "/app/.heroku/python/lib/python3.8/site-packages/django/core/handlers/base.py", line 115, in _get_response
response = self.process_exception_by_middleware(e, request)
File "/app/.heroku/python/lib/python3.8/site-packages/django/core/handlers/base.py", line 113, in _get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "/app/catalog/views.py", line 18, in rotateimage
form.save()
File "/app/.heroku/python/lib/python3.8/site-packages/django/forms/models.py", line 459, in save
self.instance.save()
File "/app/.heroku/python/lib/python3.8/site-packages/django/db/models/base.py", line 745, in save
self.save_base(using=using, force_insert=force_insert,
File "/app/.heroku/python/lib/python3.8/site-packages/django/db/models/base.py", line 793, in save_base
post_save.send(
File "/app/.heroku/python/lib/python3.8/site-packages/django/dispatch/dispatcher.py", line 173, in send
return [
File "/app/.heroku/python/lib/python3.8/site-packages/django/dispatch/dispatcher.py", line 174, in <listcomp>
(receiver, receiver(signal=self, sender=sender, **named))
File "/app/catalog/models.py", line 31, in update_image
rotate_image(fullpath)
File "/app/catalog/utilities.py", line 9, in rotate_image
image = Image.open(filepath)
File "/app/.heroku/python/lib/python3.8/site-packages/PIL/Image.py", line 2766, in open
fp = builtins.open(filename, "rb")
Exception Type: FileNotFoundError at /catalog/rotateimage
Exception Value: [Errno 2] No such file or directory: 'https://db-devsite1.s3.amazonaws.com/media/uploadImage/81c01af5-030f-42ed-b413-91eb8941675b_Kupxl37.JPG'
编辑这里是 post-保存功能有效的代码解决方案
@receiver(post_save, sender=uploadImage, dispatch_uid="update_image_profile")
def update_image(sender, instance, **kwargs):
if instance.uploadImage:
# Download instance.uploadImage from S3 to temp folder
s3_client = boto3.client('s3')
bucket_name = settings.AWS_STORAGE_BUCKET_NAME
subfolder_name = 'media/'
target_image = str(instance.uploadImage)
image_path = subfolder_name + target_image
image_name = '/tmp/image.jpg'
s3_client.download_file(bucket_name, image_path, image_name)
# Rotate image in temp folder
rotate_image(image_name)
# Upload rotated image from temp folder back to S3
s3_client.upload_file(image_name, bucket_name, image_path)
如果您的代码成功处理了旋转,那么唯一缺少的步骤是 download/upload 图像。
下载:
import boto3
s3_client = boto3.client('s3')
s3_client.download_file('mybucket', 'user1.jpg', '/tmp/image.jpg')
然后,使用您现有的代码旋转图像,最后将其上传到您想要的目的地:
s3_client.upload_file('/tmp/image.jpg', 'mybucket', 'user1.jpg')