我在这个问题上搜索了很多,但却找不到我需要的东西。我将解释我的问题:
在我的网站上,用户可以上传图片。我需要调整此图片的大小,然后在 上传之前将其转换为JPEG 。
我在Views.py中看到了一些使用方法的解决方案,但我想通过覆盖Models.py中的save()方法来实现。问题是,我发现在save方法中调整图像大小的所有解决方案都是在第一次保存后调用它(调用超级函数),这意味着它使用带宽(如果我使用CDN)什么都不做(我是对的)关于这一点?)。
感谢您的帮助
答案 0 :(得分:21)
首先,建立正确的语言是最好的。 Django和Python仅存在于服务器端。因此,他们操纵,保存或以其他方式使用的任何东西都必须首先发送到服务器。如果Django或Python要管理照片,用户必须首先将此照片上传到服务器。上传照片后,Django可以在存储文件之前自由进行更改。
如果您担心上传带宽,并且您不希望上传大文件,则必须在客户端调整照片大小并重新格式化。如果这是一个Web应用程序,可以使用Javascript完成,但不能用Python完成,因为Python不能在客户端运行像你这样的应用程序。
如果您的担忧不在于带宽,那么您可以自由地让用户“上传”#34;该文件,但随后Django调整大小并重新格式化,然后保存。
您是否正确想要覆盖照片对象的保存功能。我建议使用库来处理调整大小和重新格式化,例如sorl。
from sorl.thumbnail import ImageField, get_thumbnail
class MyPhoto(models.Model):
image = ImageField()
def save(self, *args, **kwargs):
if self.image:
self.image = get_thumbnail(self.image, '500x600', quality=99, format='JPEG')
super(MyPhoto, self).save(*args, **kwargs)
Sorl只是一个我很自信和熟悉的库,但它需要一些调整和配置。您可以查看Pillow或其他内容,只需替换覆盖self.image
的行。
我也发现了一个类似的问题here。
修改:看到了上述评论回复的更新。另请注意,如果您的Web服务器正在处理Django,并且您的文件正在保存到某些CDN上的数据库中,则此方法将起作用。在上传到您的CDN之前,图像将在网络服务器上调整大小(假设您的配置正如我所假设的那样)。
希望这有帮助!
答案 1 :(得分:7)
这是一款可以解决这个问题的应用:django-smartfields。每当上传新图像时,它也会删除旧图像。
from django.db import models
from smartfields import fields
from smartfields.dependencies import FileDependency
from smartfields.processors import ImageProcessor
class ImageModel(models.Model):
image = fields.ImageField(dependencies=[
FileDependency(processor=ImageProcessor(
format='JPEG', scale={'max_width': 300, 'max_height': 300}))
])
答案 2 :(得分:5)
EDIT4:可以找到完整的工作代码here(下面的代码仍有一些错误)
仍在战斗,但有进步^^:我正在尝试用PIL进行内存调整和转换(并且看到关于主题的问题数量,似乎我不是唯一的^^)。到目前为止我的代码(在Models.py中):
from PIL import Image as Img
import StringIO
from django.core.files import File
class Mymodel(models.Model):
#blablabla
photo = models.ImageField(uppload_to="...", blank=True)
def save(self, *args, **kwargs):
if self.photo:
image = Img.open(StringIO.StringIO(self.photo.read()))
image.thumbnail((100,100), Img.ANTIALIAS)
output = StringIO.StringIO()
image.save(output, format='JPEG', quality=75)
output.seek(0)
self.photo = File(output, self.photo.name())
super(Mymodel, self).save(*args, **kwargs)
我在“photo = File(output,photo.name())”
时遇到错误由于
编辑:对不起,这是一个简单的错误(忘记了自己。)在代码中纠正。现在我在同一行有错误“TypeError,'unicode'对象不可调用”。EDIT2:看到有关“output.getvalue()”here的内容,但不知道是否可以提供任何帮助。
EDIT3:解决了!!代码如下。
from PIL import Image as Img
import StringIO
from django.core.files.uploadedfile import InMemoryUploadedFile
class Mymodel(models.Model):
photo = models.ImageField(upload_to="...", blank=True)
def save(self, *args, **kwargs):
if self.photo:
image = Img.open(StringIO.StringIO(self.photo.read()))
image.thumbnail((200,200), Img.ANTIALIAS)
output = StringIO.StringIO()
image.save(output, format='JPEG', quality=75)
output.seek(0)
self.photo= InMemoryUploadedFile(output,'ImageField', "%s.jpg" %self.photo.name, 'image/jpeg', output.len, None)
super(Mymodel, self).save(*args, **kwargs)
答案 3 :(得分:3)
为了我自己的项目把这个放在一起,在我意识到Django ImageField上的字节和图像是单独的属性之前花了我一段时间,这个解决方案适用于Python 3.6。
def clean_image(self):
image_field = self.cleaned_data.get('image')
if image_field:
try:
image_file = BytesIO(image_field.file.read())
image = Image.open(image_file)
image.thumbnail((300, 300), Image.ANTIALIAS)
image_file = BytesIO()
image.save(image_file, 'PNG')
image_field.file = image_file
image_field.image = image
return image_field
except IOError:
logger.exception("Error during resize image")
答案 4 :(得分:1)
这对我有用,请尝试一下。我正在使用Django 2.0.6和Python 3.6.4
from django.db import models
from PIL import Image
from io import BytesIO
from django.core.files.uploadedfile import InMemoryUploadedFile
class ImageUpload(models.Model):
name = models.CharField(max_length=100)
uploadedImage = models.ImageField(upload_to='Uploads/%Y/%m/', db_column="Upload an Image")
def save(self, *args, **kwargs):
imageTemproary = Image.open(self.uploadedImage)
outputIoStream = BytesIO()
imageTemproaryResized = imageTemproary.resize( (1020,573) )
imageTemproaryResized.save(outputIoStream , format='JPEG', quality=85)
outputIoStream.seek(0)
self.uploadedImage = InMemoryUploadedFile(outputIoStream,'ImageField', "%s.jpg" %self.uploadedImage.name.split('.')[0], 'image/jpeg', sys.getsizeof(outputIoStream), None)
super(ImageUpload, self).save(*args, **kwargs)
答案 5 :(得分:1)
from django.db import models
from django.contrib.auth.models import User
from PIL import Image
class profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
bio = models.CharField(max_length=300)
location = models.CharField(max_length=99)
image = models.ImageField(default='default.jpg', upload_to='profile_pics')
def save(self):
super().save() # saving image first
img = Image.open(self.image.path) # Open image using self
if img.height > 300 or img.width > 300:
new_img = (300, 300)
img.thumbnail(new_img)
img.save(self.image.path) # saving image at the same path
此示例显示了图像调整大小后如何上传图像。 根据需要更改new_img的像素。
答案 6 :(得分:0)
这里还有另外一个对我有效的软件包,只需最少的代码修改-django-resized。
models.py
from django_resized import ResizedImageField
class Post(models.Model):
image = ResizedImageField(upload_to='uploads/%Y/%m/%d')
settings.py
DJANGORESIZED_DEFAULT_SIZE = [1024, 768]
DJANGORESIZED_DEFAULT_QUALITY = 75
DJANGORESIZED_DEFAULT_KEEP_META = True
DJANGORESIZED_DEFAULT_FORCE_FORMAT = 'JPEG'
DJANGORESIZED_DEFAULT_FORMAT_EXTENSIONS = {'JPEG': ".jpg"}
DJANGORESIZED_DEFAULT_NORMALIZE_ROTATION = True
就是这样!
答案 7 :(得分:0)
最简单的解决方案:
int main(void)
{
int iArray[3] = {100,234,567};
f1(iArray);
f2(iArray);
f3(iArray);
return EXIT_SUCCESS;
}
void f1(int ia[3]) // sized array
{
ia[0] = 1;
ia[1] = 2;
ia[2] = 3;
for (int i = 0; i < 3; i++)
{
printf("%d\n", ia[i]);
}
printf("\n");
}
void f2(int* pi) // pointer
{
*pi = 11, 12, 13;
printf("%d", *pi);
printf("\n\n");
}
void f3(int ia[]) // unsized array
{
ia[0] = 101;
ia[1] = 102;
ia[2] = 103;
for (int i = 0; i < 3; i++)
{
printf("%d\n", ia[i]);
}
}
答案 8 :(得分:0)
from PIL import Image
class Article(TimeStampedModel):
image = models.ImageField(upload_to='article_images/', null=True, blank=True)
def save(self, *args, **kwargs):
if self.image:
super().save(*args, **kwargs)
img = Image.open(self.image.path)
if img.height > 700 or img.weight > 700:
output_size = (700,700)
img.thumbnail(output_size)
img.save(self.image.path)