簡體   English   中英

使用 boto 將 Pillow 文件保存到 S3

[英]Saving a Pillow file to S3 with boto

我通過 s3boto 使用 Amazon S3 作為我的存儲后端。 我有一個帶有 ImageField 的圖像 model。 當通過管理員上傳圖像時,它已成功上傳到 S3。 我現在要做的是使用 Pillow 創建縮略圖后保存。 我已經驗證縮略圖是通過調用縮略圖的 show() 方法創建的,但由於某種原因它沒有上傳到 S3。 我認為我保存它的方式可能是錯誤的 - 如有任何建議,我們將不勝感激。

任務.py

from celery import shared_task
from .models import Image
import os
from django.core.files.storage import default_storage as storage
from PIL import Image as PillowImage

@shared_task
def create_thumbnails(pk):
    try:
        image = Image.objects.get(pk=pk)
    except Image.ObjectDoesNotExist:
        pass
    thumbnail_size = (450,200)
    filename, ext = os.path.splitext(image.image.name)
    try:
        fh = storage.open(image.image.name, 'r')
        im = PillowImage.open(fh)
        im.thumbnail(thumbnail_size)
        im.show() # TEST - This opens the resized image in Preview on my mac
        filename = filename +'_thumbnail' +ext
        new_file = storage.open(filename, 'w')
        im.save(new_file, "PNG")
        new_file.close()
    except IOError as error:
        print("cannot create thumbnail for ", filename, 'error ', error)

django 1.85

python 2.7.10

這非常有用,我用它來找到一種方法,從django直接將圖像寫入s3而不使用boto。

基本上PIL的save()方法不適用於s3,但default_storage.write()方法可以。 關鍵是使用default_storage.write()方法直接從StringIO內存文件中寫入二進制數據,如下所示:

file_to_write.write(memory_file.getvalue())

這是我在django shell(python manage.py shell)中運行的代碼來測試這個:

>>> from django.core.files.storage import default_storage as storage
>>> from PIL import Image
>>> import StringIO
>>> i = storage.open('ImageToCreate.jpg','w+')
>>> m = storage.open('ImageAlreadyOnS3.jpg','r')
>>> im = Image.open(m)
>>> im = im.resize((640,360),3)
>>> sfile = StringIO.StringIO() #cStringIO works too
>>> im.save(sfile, format="JPEG")
>>> i.write(sfile.getvalue())
>>> i.close()
>>> m.close()

它也適用於我的views.py.

我發現它很有用,因為它適用於遠程s3存儲和本地開發環境(我的筆記本電腦上的文件夾)。

最后通過谷歌搜索非常痛苦的幾個小時后工作,主要是感謝這篇博文。

tasks.py

from celery import shared_task
import os
from django.core.files.storage import default_storage as storage
from django.conf import settings
import mimetypes
import cStringIO
from PIL import Image as PillowImage
import boto
from .models import Image

@shared_task
def create_thumbnails(pk):
    try:
        image = Image.objects.get(pk=pk)
    except Image.ObjectDoesNotExist:
        pass
    try:
        thumbnail_size = (450,200)
        filename, ext = os.path.splitext(image.image.name)
        filename = filename +'_thumbnail' +ext
        existing_file = storage.open(image.image.name, 'r')
        im = PillowImage.open(existing_file)
        im = im.resize(thumbnail_size, PillowImage.ANTIALIAS)
        memory_file = cStringIO.StringIO()
        mime = mimetypes.guess_type(filename)[0]
        plain_ext = mime.split('/')[1]
        im.save(memory_file, plain_ext)

        conn  = boto.connect_s3(settings.AWS_ACCESS_KEY_ID, settings.AWS_SECRET_ACCESS_KEY)
        bucket = conn.get_bucket( 'yourbucketname', validate=False)
        k = bucket.new_key('media/' +filename)
        k.set_metadata('Content-Type', mime)
        k.set_contents_from_string(memory_file.getvalue())
        k.set_acl("public-read")
        memory_file.close()
    except Exception as error:
        print("cannot create thumbnail for ", filename, 'error ', error)

我遇到過同樣的問題。

default_storage.write() # It didn't work. it was not saving anything to s3 

@RunLoop的答案非常復雜,與我想用Django做的不同,所以我做了這個並且它有效。

    import StringIO
    from PIL import Image

首先,閱讀上傳的文件

    image = request.FILES['image'].read()  #atleast in my case 

創建一個像object這樣的文件,以便我們可以使用Image來讀取它

    image_file = StringIO.StringIO(image)
    thumbnail_image = Image.open(image_file)

將圖像調整為所需大小

    resized_thumbnail_image = thumbnail_image.resize((200, 200), Image.ANTIALIAS)

創建另一個文件,如object或inmemory文件,以便我們可以將Image實例寫入它並獲取字符串值 - 應將其傳遞給默認存儲

    resized_thumbnail_image_file = StringIO.StringIO()
    resized_thumbnail_image.save(resized_thumbnail_image_file, 'JPEG',quality=90)

    default_storage.save(save_path, ContentFile(resized_thumbnail_image_file.getvalue()))

我的第一個詳細答案,希望它有所幫助。

Stack:python 2.7 Django 1.8

請注意,使用Python3,您可能希望使用BytesIO:

from io import BytesIO

# 'image' is a PIL image object.

imageBuffer = BytesIO()
image.save(imageBuffer, format=imageType)

imageFile = default_storage.open(imageFileName, 'wb')
imageFile.write(imageBuffer.getvalue())
imageFile.flush()
imageFile.close()

一個比rotten的答案更容易理解、更可行的例子

from io import BytesIO
from PIL import Image
from django.core.files.base import ContentFile
from django.core.files.storage import default_storage
from django.contrib.staticfiles.storage import staticfiles_storage

img = Image.new('RGB', (1920, 1080), color = 'red') # <-- use this
#img = Image.open(r'C:\Users\you\Pictures\profile.jpg') # <-- or a file on your computer

buffer = BytesIO()
img.save(buffer, format='JPEG')

fp = '{path}{name}'.format(path='adminz/profile/', name='default.jpg')
f = default_storage.open(fp, 'wb')
f.write(buffer.getvalue())
f.close()

我正在使用 Django 存儲,這就是我需要弄清楚這一點的原因。 我包含了額外未使用的導入,因為在處理此主題時您經常會找到了解它們的理由。

我在項目中使用的另一個例子:

image = Image.open(photo) # <- open
cropped_image = image.crop((x, y, w + x, h + y)) # <- do something
with BytesIO() as f:
    cropped_image.save(f, format=settings.THUMBNAIL_FORMAT, quality=95) # <- save to buffer
    img = f.getvalue()

post.featured_image.save(photo.name,
                         content=ContentFile(img))

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM