在Google云存储存储桶中使用PIL更改图像大小(从GCLOUD中的VM)



这是我需要的:当用户上传图像时,请验证该图像是否超过一定大小,如果这样更改大小。此代码没有任何错误,但是保存的图像的大小没有更改。该图像位于Google云存储桶中,它在之前上传,但效果很好。欢迎任何主意。预先感谢。

from PIL import Image
from django.core.files.storage import default_storage
from google.cloud import storage
from google.cloud.storage import Blob
import io
if default_storage.exists(image_path):
    client = storage.Client()
    bucket = client.get_bucket('mybucket.appspot.com')
    blob = Blob(image_path, bucket)
    contenido = blob.download_as_string()
    fp = io.BytesIO(contenido)
    im = Image.open(fp)
    x, y = im.size
    if x>450 or y>450:
        im.thumbnail((450,450))
        im.save(fp, "JPEG")
        # im.show() here it shows the image thumbnail (thumbnail works)
        blob.upload_from_string(fp.getvalue(), content_type="image/jpeg")
        blob_dest = Blob('new_image.jpg', bucket)
        blob.download_as_string()
        blob_dest.rewrite(blob)

您在这里发生了很多额外的事情,包括将图像保存到本地文件系统,这是不必要的。这个最小的例子应该起作用:

import io 
from PIL import Image
from django.core.files.storage import default_storage
from google.cloud import storage
if default_storage.exists(image_path):
    client = storage.Client()
    bucket = client.get_bucket('mybucket.appspot.com')
    # Download the image
    blob = bucket.get_blob(data['name']).download_as_string()
    bytes = io.BytesIO(blob)
    im = Image.open(bytes)
    x, y = im.size
    if x>450 or y>450:
        # Upload the new image
        thumbnail_blob = bucket.blob('new_image.jpg')
        thumbnail_blob.upload_from_string(im.resize(450, 450).tobytes())

我已经尝试了 @dustin-ingram的解决方案,这在我身上碰巧,该文件在再次下载时最终损坏了。使用此答案中的代码,我达到了解决方案。

import io 
from PIL import Image
from google.cloud import storage
__max_size = 450, 450
image_name = 'my_images/adasdasadas7c2a7367cf1f.jpg'
client = storage.Client()
bucket = client.bucket('my-bucket')
# Download the image
blob = bucket.blob(image_name).download_as_string()
blob_in_bytes = io.BytesIO(blob)
# Translating into PIL Image object and transform
pil_image = Image.open(blob_in_bytes)
pil_image.thumbnail(__max_size, Image.ANTIALIAS)
# Creating the "string" object to use upload_from_string
img_byte_array = io.BytesIO()
pil_image.save(img_byte_array, format='JPEG')
# Create the propper blob using the same bucket and upload it with it's content type
thumbnail_blob = bucket.blob(image_name)
thumbnail_blob.upload_from_string( img_byte_array.getvalue(), content_type="image/jpeg")

不管您使用的是哪种云存储,您都可以使用此方法调整上传的图像大小,然后您可以根据需要上传图像或操纵图片:

from io import BytesIO
from PIL import Image as PilImage
import os
from django.core.files.base import ContentFile
from django.core.files.uploadedfile import InMemoryUploadedFile, TemporaryUploadedFile
def resize_uploaded_image(image, max_width, max_height):
    size = (max_width, max_height)
    # Uploaded file is in memory
    if isinstance(image, InMemoryUploadedFile):
        memory_image = BytesIO(image.read())
        pil_image = PilImage.open(memory_image)
        img_format = os.path.splitext(image.name)[1][1:].upper()
        img_format = 'JPEG' if img_format == 'JPG' else img_format
        if pil_image.width > max_width or pil_image.height > max_height:
            pil_image.thumbnail(size)
        new_image = BytesIO()
        pil_image.save(new_image, format=img_format)
        new_image = ContentFile(new_image.getvalue())
        return InMemoryUploadedFile(new_image, None, image.name, image.content_type, None, None)
    # Uploaded file is in disk
    elif isinstance(image, TemporaryUploadedFile):
        path = image.temporary_file_path()
        pil_image = PilImage.open(path)
        if pil_image.width > max_width or pil_image.height > max_height:
            pil_image.thumbnail(size)
            pil_image.save(path)
            image.size = os.stat(path).st_size
    return image

如果您是从帖子表格中获取图像,则可以执行此操作:

image = request.FILES['image']
...
image = resize_uploaded_image(image, 450, 450)
...
thumbnail_blob.upload_from_string(image.read(), image.content_type)

更好的方法是在您的形式的图像字段的干净方法中使用它:

class ImageForm(forms.Form):
    IMAGE_WIDTH = 450
    IMAGE_HEIGHT = 450
    image = forms.ImageField()
    def clean_image(self):
        image = self.cleaned_data.get('image')
        image = resize_uploaded_image(image, self.IMAGE_WIDTH, self.IMAGE_HEIGHT)
        return image

我在将您的问题与Dustin的答案相结合时取得了一些结果:

    bucket = client.get_bucket('mybucket.appspot.com')
    blob = Blob(image_path, bucket)
    contenido = blob.download_as_string()
    fp = io.BytesIO(contenido)
    im = Image.open(fp)
    x, y = im.size
    if x > 128 or y > 128:
        thumbnail_blob = bucket.blob('new_image.jpg')
        thumbnail_blob.upload_from_string(im.resize((128, 128), 2).tobytes())

2个调整大小中的2个用于重采样过滤器:使用image.neart(0(,image.lanczos(1(,image.binear(2(,image.bicubic(3(,image.box(4(或image.hamming(5(

最新更新