2

ユーザーがアップロードした画像を取得してサイズを変更し、元の画像とサイズ変更された画像を A​​mazon S3 に保存する最良の方法を見つけようとしています。

私は Django 1.5 を実行しており、PIL を使用して画像のサイズを変更し、Boto を使用して画像ファイルを S3 にアップロードしています。現在、元の画像をS3にアップロードし、PILを使用してS3パスを使用して画像を開いてサイズを変更し、サイズ変更されたバージョンをS3に保存することで機能するようになりましたが、これはほとんどないようですこれを行う効率的な方法。

ユーザーがアップロードした画像自体を使用してS3にアップロードする前に画像のサイズを変更する方法があるかどうか(PILで画像ファイル自体を開くのに問題がありました)、そしてこれが私が設定した方法よりも速いかどうか疑問に思っています物事は今。PILのドキュメントでも他の場所でも、これに対する答えが見つからないようです。私の目標の一部は、何が起こっているのかを根本的に学び、理解することであるため、これを処理するためにサードパーティのアプリを使用したくないことを言及する必要があります.

現在設定している方法よりも効率的な方法はありますか? 各ステップで何が起こっているのか、そしてなぜそのように設定することが最も理にかなっているのかについての一般的な説明が理想的です。

また、画像をサーバーに保存していたときよりも、画像を S3 にアップロードするのに時間がかかるように思われることにも言及する必要があります。S3 へのアップロード時に通常の遅延はありますか?それとも、S3 アップロードの速度を低下させる可能性のあるセットアップ方法に潜在的な何かがありますか?

4

1 に答える 1

1

HerokuのDjango+TastypieとS3のイメージウェアハウスで構成されるアーキテクチャがあります。ユーザーがフロントエンド(JSで記述)から写真をアップロードするときに私が行うことは、常にアスペクト比を維持する特定のサイズ(600 x 600最大サイズ)に写真のサイズを変更することです。これを行うためのコードを貼り付けます(機能します)。

views.py:

class UploadView(FormView):
    form_class = OriginalForm
    def form_valid(self, form):
        original = form.save()
        if  original.image_width > 280 and original.image_height > 281:
            if original.image_width > 600 or original.image_height > 600:
                original.resize((600, 600))
                if not original.image:
                    return self.success(self.request, form, None, errors = 'Error while uploading the image')
                original.save()
                up = UserProfile.objects.get(user = request.user.pk)
                #Save the images to s3
                s3 = S3Custom()
                new_image = s3.upload_file(original.image.path, 'avatar')
                #Save the s3 image path, as string, in the user profile
                up.avatar = new_image
                up.save
        else:
            return self.success(self.request, form, None, errors = 'The image is too small')       
        return self.success(self.request, form, original)

ここで私が行うことは、画像が280 x 281よりも大きいかどうか(フロントエンドのクロップスクエアがそのサイズであるかどうか)、および画像の片側が600pxよりも大きいかどうかを確認することです。その場合は、Originalクラスの(カスタム)メソッドresizeを呼び出します...

models.py:

class Original(models.Model):
    def upload_image(self, filename):
        return u'avatar/{name}.{ext}'.format(            
            name = uuid.uuid4().hex,
            ext  = os.path.splitext(filename)[1].strip('.')
        )

    def __unicode__(self):
        return unicode(self.image)

    owner = models.ForeignKey('people.UserProfile')
    image = models.ImageField(upload_to = upload_image, width_field  = 'image_width', height_field = 'image_height')
    image_width = models.PositiveIntegerField(editable = False, default = 0)
    image_height = models.PositiveIntegerField(editable = False, default = 0)  

    def resize(self, size):
        if self.image is None or self.image_width is None or self.image_height is None:
            print 'Cannot resize None things'
        else:
            IMG_TYPE = os.path.splitext(self.image.name)[1].strip('.')
            if IMG_TYPE == 'jpeg':
                PIL_TYPE = 'jpeg'
                FILE_EXTENSION = 'jpeg'
            elif IMG_TYPE == 'jpg':
                PIL_TYPE = 'jpeg'
                FILE_EXTENSION = 'jpeg'
            elif IMG_TYPE == 'png':
                PIL_TYPE = 'png'
                FILE_EXTENSION = 'png'
            elif IMG_TYPE == 'gif':
                PIL_TYPE = 'gif'
                FILE_EXTENSION = 'gif'
            else:
                print 'Not a valid format'
                self.image = None
                return
            #Open the image from the ImageField and save the path
            original_path = self.image.path
            fp = open(self.image.path, 'rb')
            im = Image.open(StringIO(fp.read()))
            #Resize the image
            im.thumbnail(size, Image.ANTIALIAS)
            #Save the image
            temp_handle = StringIO()
            im.save(temp_handle, PIL_TYPE)
            temp_handle.seek(0)
            #Save image to a SimpleUploadedFile which can be saved into ImageField
            suf = SimpleUploadedFile(os.path.split(self.image.name)[-1], temp_handle.read(), content_type=IMG_TYPE)
            #Save SimpleUploadedFile into image field
            self.image.save('%s.%s' % (os.path.splitext(suf.name)[0],FILE_EXTENSION), suf, save=False)
            #Delete the original image
            fp.close()
            os.remove(original_path)
            #Save other fields
            self.image_width = im.size[0]
            self.image_height = im.size[1]
        return

最後に必要なのは、カスタムs3メソッドを含む「ライブラリ」です。

class S3Custom(object):
    conn = S3Connection(settings.AWS_ACCESS_KEY_ID, settings.AWS_SECRET_ACCESS_KEY)
    b = Bucket(conn, settings.AWS_STORAGE_BUCKET_NAME)
    k = Key(b)
    def upload_file(self, ruta, prefix):
        try:           
            self.k.key = '%s/%s' % (prefix, os.path.split(ruta)[-1])
            self.k.set_contents_from_filename(ruta)
            self.k.make_public()
        except Exception, e:
            print e
        return '%s%s' % (settings.S3_URL, self.k.key)

設定ファイルには、AWS_ACCESS_KEY_ID、AWS_SECRET_ACCESS_KEY、AWS_STORAGE_BUCKET_NAME、S3_URLが含まれている必要があります。

于 2012-11-29T15:25:51.957 に答える